1

Generally I follow the Google style guide, which I feel aligns nicely with the way I see things. I also, almost exclusively, use boost::scoped_ptr so that only a single manager has ownership of a particular object. I then pass around naked pointers, the idea being that my projects are structured such that the managers of said objects are always destroyed after the objects that use them are destroyed.

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Smart_Pointers

This is all great, however I was just bitten by a nasty little memory stomp bug where the owner just so happened to be deleted before objects that were using it were deleted.

Now, before everyone jumps up and down that I'm a fool for this pattern, why don't I just use shared_ptr ? etc., consider the point that I don't want to have undefined owner semantics. Although shared_ptr would have caught this particular case, it sends the wrong message to users of the system. It says, "I don't know who owns this, it could be you!"

What would have helped me would have been a weak pointer to a scoped pointer. In effect, a scoped pointer that has a list of weak references, that are nulled out when the scoped pointer destructs. This would allow single ownership semantics, but give the using objects a chance to catch the issue I ran into.

So at the expense of an extra 'weak_refs' pointer for the scoped_ptr and an extra pointer for the 'next_weak_ptr' in the weak_ptr, it would make a neat little single owner, multiple user structure.

It could maybe even just be a debug feature, so in 'release' the whole system just turns back into a normally sized scoped_ptr and a standard single pointer for the weak reference.

So..... my QUESTIONS after all of this are:

  1. Is there such a pointer/patten already in stl/boost that I'm missing, or should I just roll my own?
  2. Is there a better way, that still meets my single ownership goal?

Cheers, Shane

Shane
  • 3,051
  • 3
  • 40
  • 45
  • 2
    I do not know of a standard or library implementation. If you do implement what you've described you'll end up with an implementation that is very similar to boost shared_ptr/weak_ptr stuff as you probably want to detect the case where somebody has gotten the raw pointer out of the weak_ptr and cached it. Having said that you may just want to use shared_ptr/weak_ptr and assert in your "manager" that the shared_ptr it is keeping is unique when you want to destroy the object. – Dan O Jul 28 '11 at 07:37

4 Answers4

6

 2. Is there a better way, that still meets my single ownership goal?

Do use a shared_ptr, but as a class member so that it's part of the invariant of that class and the public interface only exposes a way to obtain a weak_ptr.

Of course, pathological code can then retain their own shared_ptr from that weak_ptr for as long as they want. I don't recommend trying to protect against Machiavelli here, only against Murphy (using Sutter's words). On the other hand, if your use case is asynchronous, then the fact that locking a weak_ptr returns a shared_ptr may be a feature!

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
3

Although shared_ptr would have caught this particular case, it sends the wrong message to users of the system. It says, "I don't know who owns this, it could be you!"

A shared_ptr doesn't mean "I don't know who owns this". It means "We own this." Just because one entity does not have exclusive ownership does not mean that anyone can own it.

The purpose of a shared_ptr is to ensure that the pointer cannot be destroyed until everyone who shares it is in agreement that it ought to be destroyed.

Is there such a pointer/patten already in stl/boost that I'm missing, or should I just roll my own?

You could use a shared_ptr exactly the same way you use a scoped_ptr. Just because it can be shared doesn't mean you have to share it. That would be the easiest way to work; just make single-ownership a convention rather than an API-established rule.

However, if you need a pointer that is single-owner and yet has weak pointers, there isn't one in Boost.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Hi Nicol, yes I was being somewhat melodramatic in my "I don't know who owns this..." line, but yes, you're right ;) As to you point, I am starting to to rethink my practice of enforcing single ownership and just rolling with the shared_ptr approach. – Shane Jul 31 '11 at 08:33
1

I'm not sure that weak pointers would help that much. Typically, if a component X uses another component Y, X must be informed of Y's demise, not just to nullify the pointer, but perhaps to remove it from a list, or to change its mode of operation so that it no longer needs the object. Many years ago, when I first started C++, there was a flurry of activity trying to find a good generic solution. (The problem was called relationship management back then.) As far as I know, no good generic solution was every found; at least, every project I've worked on has used a hand built solution based on the Observer pattern.

I did have a ManagedPtr on my site, when it was still up, which behaved about like what you describe. In practice, except for the particular case which led to it, I never found a real use for it, because notification was always needed. It's not hard to implement, however; the managed object derives from a ManagedObject class, and gets all of the pointers (ManagedPtr, and not raw pointers) it hands out from it. The pointer itself is registered with the ManagedObject class, and the destructor of the ManagedObject class visits them all, and "disconnects" them by setting the actual pointer to null. And of course, ManagedPtr has an isValid function so that the client code can test before dereferencing. This works well (regardless of how the object is managed—most of my entity objects "own" themselves, and do a delete this is response to some specific input), except that you tend to leak invalid ManagedPtr (e.g. whenever the client keeps the pointer in a container of some sort, because it may have more than one), and clients still aren't notified if they need to take some action when your object dies.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Hi James, I've implemented a similar container before which effectively zeros out all references/pointers after calling a function like "objectDeleting" function. It's really just the Observer Pattern. I'm starting to think it's not really necessary for my manager case too. – Shane Jul 31 '11 at 08:31
0

If you happen to be using QT, QPointer is basically a weak pointer to a QObject. It connects itself to the "I just got destroyed" event in the pointed-to value, and invalidates itself automatically as needed. That's a seriously hefty library to pull in for what amounts to bug tracking, though, if you aren't already jumping through QT's hoops.

Dennis Zickefoose
  • 10,791
  • 3
  • 29
  • 38