views:

220

answers:

3

I have a set of shared pointers:

std::set<boost::shared_ptr<T>> set;

And a pointer:

T* p;

I would like to efficiently remove the element of set equal to p, but I can't do this with any of the members of set, or any of the standard algorithms, since T* is a completely different type to boost::shared_ptr<T>.

A few approaches I can think of are:

  • somehow constructing a new shared_ptr from the pointer that won't take ownership of the pointed to memory (ideal solution, but I can't see how to do this)
  • wrapping / re-implementing shared_ptr so that I can do the above
  • just doing my own binary search over the set

Help!

+1  A: 

If the reason for using the set is that you need to efficiently find pointers of type T, then the obvious answer is not to make it a set of shared pointers! Instead, wrap the set in a class which manages the lifetimes of the pointers that the set contains.

anon
composition over inheritance!
Eric
That seems like a large amount of work compared to the other options (that's why I didn't list it!): the _only_ time I need to lookup by pointer rather than shared_ptr is when I'm removing objects (and objects might persist beyond removal until the last user's shared_ptr is destroyed), so I can't blindly tie the lifespan of objects to their being in the container.
Autopulated
@Eric - not really. `std::set<boost::shared_ptr<T>>` is already composition, not inheritance. Neil is suggesting composing the right things, instead of composing the wrong things.
Daniel Earwicker
@Dan - I know, i just wanted to point out that the solution isn't with inheritance
Eric
+1  A: 

You can use boost::ptr_set if you want the set to have ownership of the objects, or boost::reference_wrapper if you just want the set to store references to them. If you use shared_ptr in one place in your code, you will have to use it in all places, or risk terrible crashes (dangling pointers, already deleted objects etc.). The exception is weak_ptr, a pointer that points to an object held by a shared_ptr but does not share ownership.

Space_C0wb0y
The set is one owner of the objects, but others users may persist after they are removed from the set, so `boost::ptr_set` is not appropriate.For this reason also I can't use the `reference_wrapper` or `weak_ptr`, since in both cases users may be left with dangling references.
Autopulated
Using pointers also has the risk of, well, dangling pointers. Why can you not remove the objects using a `shared_ptr`? Why do you introduce a normal pointer there?
Space_C0wb0y
effectively I want to remove from within a member function of the objects stored, so somewhere higher up the stack there is a shared_ptr referring to the object, but I don't want to have to pass it down when the `this` pointer is readily available. Basically I want to do: `removeFromSet(this)`
Autopulated
+6  A: 

Construct a shared_ptr<T> from T with a null_deleter (see boost:::shared_ptr FAQ).

That way the types are compatible and you don't have to worry about your temporary shared_ptr deleting any object.

Or, as one of the comments say, if you can change T to inherit from enable_shared_from_this you could get a correct shared ptr from your object.

Marcus Lindblom
Ah, thanks! That's the simple solution I was looking for.
Autopulated
+1 Darn, was about to post this. I dismissed it at first due to (wrong) idea that the deleter was part of the `shared_ptr` type.
Daniel Earwicker
There is actually a separate FAQ for obtaining a `shared_ptr` from `this` in the FAQ linked in this answer. There appears to be a class template called `enable_shared_from_this` that, when inherited, provides a `weak_ptr` to `this`. See http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/enable_shared_from_this.html.
Space_C0wb0y
@Space_C0wb0y: True. However, it depends if you can change T to inherit that. Not always possible.
Marcus Lindblom
I had some trouble using a shared_ptr with a null deleter: set::count returns zero even when there is a shared_ptr in the set with the same address as the one I construct... so I'm going for the `enable_shared_from_this` solution instead.
Autopulated
@Autopopulated: Strange! The == and < operators for shared_ptr are defined in terms of the address only. (I just checked)
Marcus Lindblom