2

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.

chessofnerd
  • 1,219
  • 1
  • 20
  • 40
  • 3
    With C++11, raw pointers should _only_ be used to signify no-ownership. – Mooing Duck Aug 28 '12 at 17:51
  • 1
    I would study "const vs nonconst", "pointer vs reference", "lvalue vs rvalue" and `std::unique_ptr`, `std::shared_ptr` and `std::weak_ptr`. People complain about the complex memory management issues in C++ that are painted over in other languages such as Java and C# - however there is an upside: performance. – Andrew Tomazos Aug 28 '12 at 18:11

3 Answers3

5

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.

  • @MooingDuck To be honest, I don't have a strong opinion on how references should be used in these contexts. My only guess would be using them for indicating non-owning temporary access? (Also, more than half of my answer is language agnostic, a lot of languages don't even *have* references.) –  Aug 28 '12 at 18:12
1

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.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

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.

zeboidlund
  • 9,731
  • 31
  • 118
  • 180
  • 1
    The only reason I can think of for a class to return a raw pointer is if it needs to return a non-owning "reference" to a possibly non-existant member via `NULL`. In all other cases, a reference, smart pointer, or value should be returned. There's no reason to return a reference to a raw pointer. – Mooing Duck Aug 28 '12 at 17:47
  • @MooingDuck - what about a singleton? I'd rather be able to manage a shared instance through a reference to a pointer than dealing with a raw pointer by itself. That way, I don't have to worry about freeing the memory when I'm finished with it. – zeboidlund Aug 28 '12 at 18:01
  • I think it's rather rare for OO objects to be managed by any of the usual smart pointers. MooningDuck's suggestion of returning a reference instead of a pointer is somewhat valid, but it goes against the grain of OO tradition, and makes it awkward if you want to deal with several different objects at different times; references can't be reseated, so you end up using a pointer, and taking the address of the reference. (And of course, smart pointers are rarely appropriate for OO type objects.) – James Kanze Aug 28 '12 at 18:04
  • 1
    @aboutblank: Setting aside the debate about if you should have a singleton to start with, there's no reason to have _any_ pointer for a singleton. Use references. – Mooing Duck Aug 28 '12 at 18:05
  • 1
    @JamesKanze: My statement was in the context of return values, since that's how I interpreted the question. You're right that if you need to reseat a local "reference" to a class' member, then that needs to be a raw pointer. I fail to see how returning a reference rather than a pointer is against OO tradition in any way. And smart pointers are almost always appropriate for OO type objects. – Mooing Duck Aug 28 '12 at 18:08
  • @MooingDuck I was thinking in terms of what you are doing with a return value. If I have a local variable which needs to be reseated, initializing or assigning it from a function which returns a reference is awkward: `T* var = &someFunc();` Because this situation is endemic in OO code, a lot of OO functions return pointers, rather than references, even though the return value can never be null. (And normally, I'd agree with you that if the return value cannot be null, you should return a reference. This is just another element to take into consideration.) – James Kanze Aug 29 '12 at 09:12
  • @MooingDuck If the object is truly OO, it will take care of managing its own lifetime. In no case should it be put into a `shared_ptr`. If for some reason, logical creation can't be done entirely in the constructor, then it would probably be appropriate to hold it in a `unique_ptr` until it is truly complete, and ready to take on its own responsibilities. – James Kanze Aug 29 '12 at 09:16
  • @JamesKanze: http://en.wikipedia.org/wiki/Object-oriented_programming#Fundamental_features_and_concepts makes no mention of objects managing their own lifetimes, I can find nothing that hints at that, and I've never heard of such a thing. In fact "Manager" classes which manage lifetimes (are in general a bad idea) are very common in OO code. Do you have a source I can look at? – Mooing Duck Aug 29 '12 at 16:09
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/15972/discussion-between-mooing-duck-and-james-kanze) – Mooing Duck Aug 29 '12 at 16:19
  • @MooingDuck Wikipedia is hardly a reference, but in this case, they probably didn't mention it because it is implicitly obvious in the more general definition: objects have behavior, and in general manage themselves in every way. A window object, for example, will catch events like a click on the cross, and auto destruct in reaction to it; a session object will auto-destruct when it receives the command to end the session, etc. – James Kanze Aug 29 '12 at 16:40