[smart_ptr] Sole ownership of shared_ptr?

View: New views
6 Messages — Rating Filter:   Alert me  

[smart_ptr] Sole ownership of shared_ptr?

by Joseph Thomson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi everyone,

Over the past few days I have been trying to integrate Boost smart pointers into my system, which is basically a manager (ObjectManager) class which creates, destroys, and keeps track of instances of another class (Object).

The manager keeps a std::map of instances of type shared_ptr.  The manager has a createObject() method which returns a shared_ptr instance to the user, thus the user becomes an owner of the object, alongside the manager.  My problem arises because I want objects to _always_ be destroyed when the manager method destroyObject() is called.  I realise that part of the reason to use smart pointers is to prevent data from being deleted while a reference to it still exists, but I figure they are still worth using just for the safety aspect.

My specific reasons for wanting the manager to be able to destroy the objects on command are:

1.) The manager may keep track of the objects, but the objects are used elsewhere in the system (until their destruction).
2.) I don't want to put the responsibility with the user (me!) to have to delete all references to the object in order for it to be deleted.  Even if I pass back a weak_ptr, it is likely that the user will store a locked version of the pointer for convenience.
3.) I am using lua, which has no C-style "delete" command, and handles object deletion in its own time.  Thus, even if all references to the object have been deleted in lua, the object may not actually be deleted straight away (unless you invoke deletion by calling collectgarbage(), which is a very messy solution).

Anyway, I came up with a solution, but am not sure if there is any better or cleaner way.  I am relatively new to smart pointers and the whole idea of virtual methods, so if I use the wrong terminology I apologise.  Here goes:

I have an abstract ObjectInterface class, which outlines all the methods that the user will access.  I then have an Object class, which is of type ObjectInterface, and implements its abstract methods.  The ObjectManager will, as before, create and store a map of shared_ptr references.  However, instead of returning a shared_ptr to the user, the ObjectManager::createObject() method now creates a shared_ptr<ObjectHandle> which it returns to the user.  ObjectManager doesn't store a reference to the handle, so the user is the sole owner of that.  ObjectHandle (I'm not sure this is the correct use of the term "Handle"?) is also of type ObjectInterface, but in its constructor it takes a shared_ptr reference from the ObjectManager, which it stores internally as a weak_ptr (so that ObjectManager remains the sole owner of Object).  It implements the ObjectInterface methods by forwarding calls from the user to the Object, but only if the weak_ptr hasn't expired.  I am also storing a raw pointer to the Object in ObjectHandle, so that it doesn't have to call shared_ptr<>::lock() every time it needs to forward a call; I think this is reasonable to do since I never copy the pointer, and certainly won't delete it.

Attached is a fully working example that I have tried to make as concise and clear as possible.  Maybe my solution is the best one and my question seems stupid, or maybe there is a far simpler way and my solution seems stupid, but either way I am asking because I am unsure about this kind of thing in general.

Thanks very much for any help in advance!

Joe

smart_ptr_example.cpp

Parent Message unknown Re: [smart_ptr] Sole ownership of shared_ptr?

by Richard L. Aurbach :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Apr 6, 2008, at 5:48 PM, Joseph Thomson wrote:
Hi everyone,

Over the past few days I have been trying to integrate Boost smart pointers
into my system, which is basically a manager (ObjectManager) class which
creates, destroys, and keeps track of instances of another class (Object).

The manager keeps a std::map of instances of type shared_ptr.  The manager
has a createObject() method which returns a shared_ptr instance to the user,
thus the user becomes an owner of the object, alongside the manager.  My
problem arises because I want objects to _always_ be destroyed when the
manager method destroyObject() is called.  I realise that part of the reason
to use smart pointers is to prevent data from being deleted while a
reference to it still exists, but I figure they are still worth using just
for the safety aspect.

I am also in the position of attempting to integrate shared_ptr into my application framework, so I am definitely a neophyte in this area. (So please take my comments with a grain of salt.) However, I have a couple of thoughts.

(1) Your idea of storing both a weak_ptr and a true pointer to the object strikes me as dangerous. Any time you use the true pointer instead of locking the weak_ptr, you run the risk that the true pointer is not valid. This would, of course, invalidate one of the major points in using the shared_ptr/weak_ptr mechanism in the first place. I don't think that the overhead of converting the weak_ptr via lock() is sufficiently high to forego the advantages of the mechanism. But of course, only performance testing can verify that. [My own bias is to build a safe mechanism first, then only weaken it if performance measurements verify that this step is necessary.]

(2) If you have, in fact, built a mechanism where you *know* that it is safe to use the true pointer instead of converting the weak_ptr, then I wonder if starting with a shared_ptr strategy is the best way to go in the first place. Since you only want one lock on the file (rather than shared ownership), wouldn't it be better to use auto_ptr? That pattern seems better suited to your overall approach -- if (and only if) you can be sure that a user will never use a deleted true pointer.

Cheers,

Rick Aurbach, Ph.D.
President and Chief Engineer
Aurbach & Associates, Inc.
8233 Tulane Avenue, Suite B
St. Louis, MO 63132

eMail:    support@... [business]
               rick@... [personal]
Fax:        314/678-0869
Phone:   800/774-7239
                314/726-1321

"If it ain't broke and you haven't fixed it recently,  it probably needs to be rewritten."  - Richard Aurbach (1948- )
"Beware of bugs in the above code; I have only proved it correct, not tried it." - Donald Knuth, computer scientist (1938- )
"If in the last few years you haven't discarded a major opinion or acquired a new one, check your pulse. You may be dead." - Gelett Burgess (1866-1951)
"A life spent making mistakes is not only more honorable, but more useful than a life spent doing nothing." - George Bernard Shaw (1856-1950)
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong." -Richard Feynman (1918-1988)
"The most likely way for the world to be destroyed, most experts agree, is by accident. That's where we come in; we're computer professionals. We cause accidents." - Nathaniel Borenstein (1957-)




_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: [smart_ptr] Sole ownership of shared_ptr?

by Joseph Thomson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


Richard L. Aurbach wrote:
(1) Your idea of storing both a weak_ptr and a true pointer to the  
object strikes me as dangerous. Any time you use the true pointer  
instead of locking the weak_ptr, you run the risk that the true  
pointer is not valid. This would, of course, invalidate one of the  
major points in using the shared_ptr/weak_ptr mechanism in the first  
place. I don't think that the overhead of converting the weak_ptr via  
lock() is sufficiently high to forego the advantages of the mechanism.  
But of course, only performance testing can verify that. [My own bias  
is to build a safe mechanism first, then only weaken it if performance  
measurements verify that this step is necessary.]

(2) If you have, in fact, built a mechanism where you *know* that it  
is safe to use the true pointer instead of converting the weak_ptr,  
then I wonder if starting with a shared_ptr strategy is the best way  
to go in the first place. Since you only want one lock on the file  
(rather than shared ownership), wouldn't it be better to use auto_ptr?  
That pattern seems better suited to your overall approach -- if (and  
only if) you can be sure that a user will never use a deleted true  
pointer.
Thanks for your reply.  Well, now that I think about it my method is not thread safe.  The pointer could be deleted at any point during its use.  I may re-consider since I haven't ruled out the use of multi-threading in the future.  However, with a single thread, doesn't checking that the weak_ptr hasn't expired before any use of the raw pointer assure that the pointer is valid (assuming that the Object doesn't unexpectedly trigger its deletion in one of its methods)?  This method still requires use of a weak_ptr for validation, and therefore auto_ptr wouldn't be sufficient, unless I am missing something?

After a quick test of lock() vs. expired() vs. no check at all in my example, with 1,000,000,000 iterations of each I get 49 seconds with no check, 59 seconds with an expired() check, and 296 seconds when locking.  So although locking is 25 times slower, it seems sufficiently fast enough to use in my application.

Cheers,

Joe

Re: [smart_ptr] Sole ownership of shared_ptr?

by Joseph Thomson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Actually, I think I have a better way which uses auto_ptr (or the boost ptr containers) as you suggested.  It still isn't thread safe, but this isn't of immediate concern, and there are other methods for this anyway.

Before, I was storing a map of shared_ptrs in the ObjectManager and a weak_ptr reference in any ObjectHandles to check if the object is still valid.  Instead:

- A map of auto_ptrs (or a ptr_map of Objects) would be stored in the ObjectManager.
- On its creation, Object would create and store a shared_ptr<ObjectHandle>, passing a raw pointer to it in the process (don't worry, this is still safe).
- Any user wanting to get access to the Object would request an ObjectHandle from ObjectManager, which would in turn request a copy of Object's shared_ptr<ObjectHandle>.
- On its destruction (by ObjectManager), Object would inform its ObjectHandle of its destruction, and ObjectHandle would set an internal flag to indicate that it is expired.
- ObjectHandle would handle any requests from the user by first checking the expiry flag, and then forwarding the call to Object using its stored raw pointer.  The expiry flag is set by the Object itself, so there is no chance of the pointer being invalid when called.

Any advice/thoughts are appreciated.

Cheers,

Joe

Parent Message unknown Re: [smart_ptr] Sole ownership of shared_ptr?

by Richard L. Aurbach :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Apr 7, 2008, at 11:00 AM, Joseph Thomson wrote:
Actually, I think I have a better way which uses auto_ptr (or the boost ptr
containers) as you suggested.  It still isn't thread safe, but this isn't of
immediate concern, and there are other methods for this anyway.

Before, I was storing a map of shared_ptrs in the ObjectManager and a
weak_ptr reference in any ObjectHandles to check if the object is still
valid.  Instead:

- A map of auto_ptrs (or a ptr_map of Objects) would be stored in the
ObjectManager.
- On its creation, Object would create and store a shared_ptr<ObjectHandle>,
passing a raw pointer to it in the process (don't worry, this is still
safe).
- Any user wanting to get access to the Object would request an ObjectHandle
from ObjectManager, which would in turn request a copy of Object's
shared_ptr<ObjectHandle>.
- On its destruction (by ObjectManager), Object would inform its
ObjectHandle of its destruction, and ObjectHandle would set an internal flag
to indicate that it is expired.
- ObjectHandle would handle any requests from the user by first checking the
expiry flag, and then forwarding the call to Object using its stored raw
pointer.  The expiry flag is set by the Object itself, so there is no chance
of the pointer being invalid when called.

Any advice/thoughts are appreciated.

Cheers,

Joe

Joe,

Suppose that: (a) ObjectManager uses shared_ptrs, not auto_ptrs, 
and (b) the base class of all Objects derives from boost::tr1::enable_shared_from_this.

Then suppose the logic of ObjectHandle was something like:

shared_ptr<Object> ptr = Object->shared_from_this();
if (ptr) {
ptr->perform-requested-action();
}
// shared ptr is reset when it goes out of scope


Wouldn't this:
>> preserve the single point of deletion (since the shared_ptr above is local).
>> be thread-safe (because 'ptr' prevents the object from being deleted until the operation is complete.

Or am I overlooking something really obvious in my (perhaps overly-)quick response?

Cheers,

Rick


_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Re: [smart_ptr] Sole ownership of shared_ptr?

by Daniel J. Kelly :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I had recently run into a similar problem, trying to use shared_ptr as a
giant hammer to be used in every case. My problem was with a multi-threaded
simulation. I was using a factory object to create the major components of
this system. These components then would execute in their own thread, with
various association between these components, all implemented in terms of
smart_ptrs. I had properly synchronized access to these components, and
everything worked fine -- most of the time.  It seems that if one of the
components was short-lived, it could actually execute and be "destroyed"
before the factory function released its shared_ptr. I put "destroyed" in
quotes because the factory function was not allowing the destruction until a
later time. This of course resulted in a deadlock.

I guess the moral of the story is that although smart_ptrs can eliminate a
whole class of lifetime management problems, they are not the solution when
you want to actively control the lifetime of your objects. If your
ObjectManager is the sole object managing the lifetime of your Objects, why
not just use raw pointers? Since ObjectManager needs to be able to destroy
the objects at a particular time (its destruction), clients of these objects
must already have some other method of determining if they are referencing a
valid object, so they could check before dereferencing the pointer.

Another possibilty is to track your objects as shared_ptrs, but only return
weak_ptrs to the clients. Client needs to derefence the pointer, it simply
converts to a shared_ptr. Just make sure you use it then lose it -- don't
store the shared_ptr anywhere.

As for your interface heirarchy, I would have to look at the code to comment
more. However, it seems that if you use the smart_ptr/weak_ptr method I
outlined, you would be able to simplify your design considerably.

Hope this helps,
Dan

-----Original Message-----
From: boost-users-bounces@...
[mailto:boost-users-bounces@...] On Behalf Of Joseph Thomson
Sent: Sunday, April 06, 2008 3:41 PM
To: boost-users@...
Subject: [Boost-users] [smart_ptr] Sole ownership of shared_ptr?


Hi everyone,

Over the past few days I have been trying to integrate Boost smart pointers
into my system, which is basically a manager (ObjectManager) class which
creates, destroys, and keeps track of instances of another class (Object).

The manager keeps a std::map of instances of type shared_ptr.  The manager
has a createObject() method which returns a shared_ptr instance to the user,
thus the user becomes an owner of the object, alongside the manager.  My
problem arises because I want objects to _always_ be destroyed when the
manager method destroyObject() is called.  I realise that part of the reason
to use smart pointers is to prevent data from being deleted while a
reference to it still exists, but I figure they are still worth using just
for the safety aspect.

My specific reasons for wanting the manager to be able to destroy the
objects on command are:

1.) The manager may keep track of the objects, but the objects are used
elsewhere in the system (until their destruction).
2.) I don't want to put the responsibility with the user (me!) to have to
delete all references to the object in order for it to be deleted.  Even if
I pass back a weak_ptr, it is likely that the user will store a locked
version of the pointer for convenience.
3.) I am using lua, which has no C-style "delete" command, and handles
object deletion in its own time.  Thus, even if all references to the object
have been deleted in lua, the object may not actually be deleted straight
away (unless you invoke deletion by calling collectgarbage(), which is a
very messy solution).

Anyway, I came up with a solution, but am not sure if there is any better or
cleaner way.  I am relatively new to smart pointers and the whole idea of
virtual methods, so if I use the wrong terminology I apologise.  Here goes:

I have an abstract ObjectInterface class, which outlines all the methods
that the user will access.  I then have an Object class, which is of type
ObjectInterface, and implements its abstract methods.  The ObjectManager
will, as before, create and store a map of shared_ptr references.  However,
instead of returning a shared_ptr to the user, the
ObjectManager::createObject() method now creates a shared_ptr<ObjectHandle>
which it returns to the user.  ObjectManager doesn't store a reference to
the handle, so the user is the sole owner of that.  ObjectHandle (I'm not
sure this is the correct use of the term "Handle"?) is also of type
ObjectInterface, but in its constructor it takes a shared_ptr reference from
the ObjectManager, which it stores internally as a weak_ptr (so that
ObjectManager remains the sole owner of Object).  It implements the
ObjectInterface methods by forwarding calls from the user to the Object, but
only if the weak_ptr hasn't expired.  I am also storing a raw pointer to the
Object in ObjectHandle, so that it doesn't have to call shared_ptr<>::lock()
every time it needs to forward a call; I think this is reasonable to do
since I never copy the pointer, and certainly won't delete it.

Attached is a fully working example that I have tried to make as concise and
clear as possible.  Maybe my solution is the best one and my question seems
stupid, or maybe there is a far simpler way and my solution seems stupid,
but either way I am asking because I am unsure about this kind of thing in
general.

Thanks very much for any help in advance!

Joe

http://www.nabble.com/file/p16528658/smart_ptr_example.cpp
smart_ptr_example.cpp
--
View this message in context:
http://www.nabble.com/-smart_ptr--Sole-ownership-of-shared_ptr--tp16528658p1
6528658.html
Sent from the Boost - Users mailing list archive at Nabble.com.

_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users


_______________________________________________
Boost-users mailing list
Boost-users@...
http://lists.boost.org/mailman/listinfo.cgi/boost-users