boost::shared_ptr: When to use it and when NOT to use it.

Started by
11 comments, last by chairthrower 16 years ago
Quote:Original post by NotAYakk
No?

shared_ptr means that any object with a shared_ptr reference to the thing in question can extend it's lifetime.


Ah, I'm just looking at things a different way; a shared_ptr will keep the thing alive until the last bit of code that uses it has dissappeared. So while you would say that code is keeping it around, I would say that shared_ptr ensures that the life of a resource is as short as it safely can be (if used carefully).

Quote:shared_ptr uses pointer semantics on assign. Ie, a = b means that a points to what b pointed to, and a constructed from b means a refers to the same thing as b.

Reference semantics a=b means what a points to is given the value of what b points to, and a constructed from b means that a refers to the same thing as b.


I tend not to distinguish between pointer and reference semantics and lump them under the same "referring to the same underlying object once constructed" heading.
as the value of b.

Quote:pointer semantics != reference semantics != value semantics.


It's a language difference. I agree with what you are saying, I'm just not as rigorous with my definitions as I might be.

Quote:Lastly, shared_ptr is a reference counted pointer, not a garbage collected pointer.


Some people would classify reference counting as a naive kind of garbage collection (hence the "depending on one's definition of garbage collection" part); if the definition of garbage collection is to release a resource when nothing is referring to it any longer, reference counting would fall under it (in cycle-free situations).

Yeah, so I'm in agreement. I will go away now :)
Advertisement
The situation when a single point in my application must control the release of a given resource is when I use shared_ptr internally and give out weak_ptr's to other objects that must reference the resource.

This prevents references to deleted memory, and all of the bizarre errors that that can lead to, and has the upside of being easier to debug. It's not a panacea, but it converts a class of really nasty errors, to something more manageable.



Avoid shared_ptr's in the binding of callbacks/events from sources/producers since they will keep the observer/consumer/sink object alive when its the only reference having a hold on the object. my approach is to bind a weak_ptr<> and test whether its alive before either calling or erasing the partially bound method from the event source site. An alternative approach would be to use a sort of reverse notification and employ an event which gets sent back to to the event producer to tell it to unbind the observers bound method when the observer is destroyed. its possible to place these in the custom Deleter of the shared_ptr that holds the observer but it feels a bit unnatural and over-engineered.

Also I think shared_ptr's can almost imply structuring an applications object graph in a tree structure otherwise you run a high risk of circular dependencies - possibly a very judicious use of weak references could be used to mitigate but the chances of something going wrong is high and it feels a bit like a workaround hack to me. there's a bit of an analogy here with the MS-office object models that use reference counted COM components and the manner in which they are structured in a tree like pattern as a means to avoid cyclic graphs/dependencies.

otherwise shared_ptr's are the best thing to happen to c++. One case where its possible to consider extending the use of shared pointer application is for resources that are not memory. You are permitted to pass a custom resource cleanup function to the shared pointer in place of the default delete. In effect you can define the policy for clean-up at the point of assignment.

An example from some db wrapper code of mine where the c api cleanup function PQfinish() for a database connection is bound as the custom deleter of the shared pointer.

/* Make a connection to the database */
PGconn *conn1 = PQconnectdb(conninfo.c_str());
/* bind clean up function */
shared_ptr< PGconn> conn( conn1, bind( &PQfinish, _1));

This feels cleaner to me than holding the raw pointer in an enclosing class and then remembering to call PQfinish() in that classes destructor to guarantee the connection wont leak if an exception is called.




This topic is closed to new replies.

Advertisement