function returns T*, I want to put that into a shared_ptr
I have a few newb questions: I have the following classes class Base { Base(); virtual ~Base(); virtual doStuff(); } class Foo: public Base { doStuff(); } class FooContainer { createFoos(int numOfFoos); Foo* getFoo(int indexToFoo); Destroy(); } class BaseContainer { void addObj(boost::shared_ptr<Base> obj); } How do I cast the pointer returned from FooContainer::getFoo(), as something I can pass to BaseContainer::addObj ? Is this correct to do this? Assuming I cant change the implementation of FooContainer or the BaseContainer interface. The BaseContainer interface should not have a special case for adding Foo's. Good practise tells me I shouldn't create a temporary either. I do not want the shared_ptr in BaseContainer to call delete on Foo (I will manually call FooContainer::Destroy() ---- Now, what happens if I instead want FooContainer to only be responsible for creating the Foo objects, and not be responsible for deleting them. Instead I want the shared_ptr to call delete when the objects reference count reaches 0. How would that done? Thanks in advance, Josh S
On Sat, May 20, 2006 at 02:27:47PM +0800, Josh S wrote:
class FooContainer { createFoos(int numOfFoos); Foo* getFoo(int indexToFoo); Destroy(); }
class BaseContainer { void addObj(boost::shared_ptr<Base> obj); }
How do I cast the pointer returned from FooContainer::getFoo(), as something I can pass to BaseContainer::addObj ?
x.addObj(boost::shared_ptr<Foo>(y.getFoo()); However, if addObj doesn't store a shared_ptr internally, the last shared_ptr to this Foo would be destroyed directly after returning from this function. That means that the Foo would be destroyed too. If you want to be sure it sticks around, you need to keep at least one boost::shared_ptr<Foo> to this object around. For example: boost::shared_ptr<Foo> ptr(y.getFoo()); x.addObj(ptr); // Use ptr until you are completely done with this object. If you need to keep it, always keep a copy of the shared_ptr.
Is this correct to do this? Assuming I cant change the implementation of FooContainer or the BaseContainer interface.
It seems pretty awkward. The risc seems to be that you destroy the last shared_ptr (and thus the Foo) at the moment that you still have a Foo* around. Therefore, this is only safe when: 1) getFoo() always returns a NEW Foo instance, allocated with new. 2) It doesn't even store a Foo* internally. 3) You turn it immediately into a shared_ptr and use that.
The BaseContainer interface should not have a special case for adding Foo's.
Good practise tells me I shouldn't create a temporary either.
I do not want the shared_ptr in BaseContainer to call delete on Foo (I will manually call FooContainer::Destroy()
Because it is unclear what FooContainer::Destroy() does, it might be necessary that it is being called, because of side-effects next to deleting the Foo. That gives a problem though if you already destroyed the last shared_ptr, then the Foo is already destroyed - so the call to delete by FooContainer::Destroy() will result in an undefined core dump (pun intended). And if you still have a shared_ptr around, then you can't safely destroy that afterwards, because it would attempt to delete the Foo object twice.
Now, what happens if I instead want FooContainer to only be responsible for creating the Foo objects, and not be responsible for deleting them. Instead I want the shared_ptr to call delete when the objects reference count reaches 0. How would that done?
Just do
boost::shared_ptr<Foo> ptr(y.getFoo());
and only work with boost::shared_ptr<Foo> objects from then on.
Never call FooContainer::Destroy, and you should be fine provided
that FooContainer doesn't keep an internal Foo* that it will access
or return on other occassions, and provided that FooContainer::Destroy
doesn't have side effects besides deleting the object.
Somehow I doubt this is possible.
My own solution would be to wrap the Foo* in a separate object and
store that in the FooContainer.
// Somewhere
boost::shared_ptr<FooPointer> fp;
// Elsewhere
fp = new FooPointer(y, y.getFoo());
x.addObj(fp);
Then, as soon as you stop using fp because the last shared_ptr<FooPointer>
is destroyed, ~FooPointer should call y.Destroy(Foo*)
(that is, I assume you meant Destroy(Foo*) and not Destroy()...)
Obviously, this isn't automatically safe. You shouldn't return Foo*'s from
FooPointer for example. But at least it helps solve the double delete problem.
I guess that defining FooPointer::operator->() to return a Foo* would be usable though.
--
Carlo Wood
Josh S wrote:
I have a few newb questions:
I have the following classes
class Base { Base(); virtual ~Base(); virtual doStuff(); }
class Foo: public Base { doStuff(); }
class FooContainer { createFoos(int numOfFoos); Foo* getFoo(int indexToFoo); Destroy(); }
class BaseContainer { void addObj(boost::shared_ptr<Base> obj); }
How do I cast the pointer returned from FooContainer::getFoo(), as something I can pass to BaseContainer::addObj ? Is this correct to do this? Assuming I cant change the implementation of FooContainer or the BaseContainer interface. The BaseContainer interface should not have a special case for adding Foo's.
Good practise tells me I shouldn't create a temporary either.
I do not want the shared_ptr in BaseContainer to call delete on Foo (I will manually call FooContainer::Destroy()
If you can be certain that the Foo objects will outlive their shared pointers (i.e. no shared_ptr<Foo> will ever be accessed after FooContainer::Destroy() has been called), you can create shared_ptrs for Foos with a 'null deleter', which will prevent the shared_ptr from deleting the object when its use_count hits zero. Go to http://www.boost.org/libs/smart_ptr/sp_techniques.html#static for an example of this technique.
Now, what happens if I instead want FooContainer to only be responsible for creating the Foo objects, and not be responsible for deleting them. Instead I want the shared_ptr to call delete when the objects reference count reaches 0. How would that done?
If you can be certain that FooContainer won't try to delete the objects itself or pass them to another piece of code that might and that no raw Foo pointer will be used to initialize more than one shared Foo pointer, then you can safely create regular shared_ptrs from the Foo pointers. Just be aware that in either case, "be certain" means more than just, "I know going to write it that way." It should also mean, "I know that five years from now when someone modifies my code, they won't be tempted to screw this up." If neither of these solutions are right for you, you might try browsing the entire page that I referenced earlier (http://www.boost.org/libs/smart_ptr/sp_techniques.html). It's full of great tips for using shared pointers in tricky situations. If there's a good solution to your problem, you'll probably find it there. HTH, Beth
participants (3)
-
Beth Jacobson
-
Carlo Wood
-
Josh S