Question

How do pointers work with the concepts of Object oriented programming?

As I understand it (and please recognize, I'm classified as an ID-10T), the main tenet of OOP is containment and keeping management responsibility (memory/implementation/etc.) contained within the class; but when an object's method returns a pointers it seems like we are 'popping' the object. Now, somebody might need to worry about:

  1. Are they supposed to delete the pointer's associated object?
  2. But what if the class still needs the object?
  3. Can they change the object? If so, how? (I recognize const might solve this issue)
  4. and so forth...

It seems the user of the object now needs to know much more about how the class works and what the class expects of the user. It feels like a "cat's out of the bag" scenario which seems to slap in the face of OOP.

NOTE: I notice this is a language independent question; however, I was prompted to ask the question while working in a C++ environment.

Was it helpful?

Solution

What you describe are ownership issues. These are orthogonal (i.e. independent, you can have either without the other or even both) to object orientation. You have the same issues if you do not use OOP and juggle pointers to POD structs. You don't have the issue if you use OOP but solve it somehow. You can (try to) solve it using more OOP or in another way.

They are also orthogonal to the use of pointers (unless you nit pick and extend the definition of pointer). For example, the same issues arise if two separate places hold indices into an array and mutate, resize and ultimately delete the array.

In C++, the usual solution is to select the right smart pointer type (e.g. return a shared pointer when you wish to share the object, or a unique pointer to signify exclusive ownership), along with extensive documentation. Actually, the latter is a key ingredient in any language.

One OOP-related thing you can do to help this is encapsulation (of course, you can have encaptulation just fine without OOP). For instance, don't expose the object at all, only expose methods which query the object under the hood. Or don't expose raw pointers, only expose smart pointers.

OTHER TIPS

For starters... You can't have polymorphism without pointers or references. In C++, traditionally, objects are copied, and have (for the most part) automatic storage duration. But copy doesn't work with polymorphic objects—they tend to get sliced. And OO also often means identity, which in turn means you don't want copy. So the solution is for the object to be dynamically allocated, and to pass around pointers. What you do with them is part of the design:

If the object is logically part of another object, then that object is responsible for its lifetime, and objects which receive the pointer should take steps to ensure that they don't use it after the owning object disappears. (Note that this is true even in languages with garbage collection. The object won't disappear as long as you've got a pointer to it, but once the owning object is invalid, the owned object may become invalid as well. The fact that the garbage collector won't recycle the memory won't guarantee that the object you point to is usable.)

If the object is a first class entity itself, rather than being logically part of another object, then it should probably take care of itself. Again, other objects which may hold a pointer to it must be informed if it ceases to exist (or becomes invalid). The use of the Observer pattern is the usual solution. Back when I started C++, there was a fashion for "relationship management", with some sort of management classes where you registered relationships, and which supposedly ensured that everything worked out OK. In practice, they either didn't work, or didn't do any more than the simple observer pattern, and you don't hear any more of them today.

For the most part, your precise questions are part of the contract that each class has to establish for each of its functions. For true OO classes (entity objects), you should probably never delete them: that's there business, not yours. But there are exceptions: if you're dealing with transactions, for example, a deleted object cannot be rolled back, so when an object decides to delete itself, it will usually register this fact with the transaction manager, who will delete it as part of the commit, once it's established that roll back won't be necessary. As for changing the object, that's a question of the contract: in a lot of applications, there are mapping objects, which are used to map an external identifier of some sort to the object. With the goal, often, of being able to modify the object.

From my understanding and experience, it generally revolves around what it is that you are trying to do as well as the language using pointers (e.g. C++ vs Objective-C).

Usually, though, in C++ terms, I've found that it's best to return either a reference to a smart pointer (such as std::shared_ptr) by reference (perhaps even const reference, depending on the situation), or simply hide the pointer in the class, and if it NEEDS to be accessed or used by something outside of it, use a getter method which either copies the pointer and returns that, or returns a reference to a pointer (granted, AFAIK ref-to-ptr is only possible in C++). If someone doesn't know that you shouldn't delete a ref-to-ptr in most situations (of course, if its deallocation is handled by the class internally), you should really think twice about whether or not they're ready to be doing C++ stuff on your team.

It's fairly common to just use public references for class members if they can be stack allocated (i.e., if they won't take up too much memory), while managing heap allocated objects internally. If you need to set the class member outside of the class, it's possible to just use a set method which takes the required value, rather than access it directly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top