Polymorphic Smart Pointers

Started by
9 comments, last by chairthrower 15 years, 10 months ago
Is there a way that I can use polymorphism with smart pointers? More specifically, I have a std::stack of boost::shared_ptr<Base>. But when I tried stack.push(new Derived), the compiler gave me the following error:
no matching function for call to `std::stack<boost::shared_ptr<Base>, std::deque<boost::shared_ptr<Base>, std::allocator<boost::shared_ptr<Base> > > >::push(Derived*)' 
note C:\MinGW\include\c++\3.4.5\bits\stl_stack.h:191 candidates are: void std::stack<_Tp, _Sequence>::push(const typename _Sequence::value_type&) [with _Tp = boost::shared_ptr<Base>, _Sequence = std::deque<boost::shared_ptr<Base>, std::allocator<boost::shared_ptr<Base> > >]
Is there a way to do this?
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Advertisement
Try
stack.push( boost::shared_ptr<Base>( new Derived ) );
Just to add to the above post, it is potentially dangerous to use an unnamed temporary shared_ptr as it has the potential to cause a memory leak.

Something like this would be a better alternative.

boost::shared_ptr<Base> obj(new Derived(/*constructor arguments here*/));stack.push(obj);
Quote:Original post by vtchill
Just to add to the above post, it is potentially dangerous to use an unnamed temporary shared_ptr as it has the potential to cause a memory leak.

Something like this would be a better alternative.

*** Source Snippet Removed ***


Actually it isn't a problem in that case. It would only be a problem if the function accepted multiple arguments.

reference
Sweet, thanks to all! I'll try it out. I'm getting to the point where I'm using more and more polymorphic objects and I don't want to worry about memory leaks, so I figured I'd try to use some smart pointers for some extra safety.

[edit]

Works perfectly!
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
To get back to the original post, a boost::shared_ptr<Base> can definitely be set to point to a Derived. I don't know why the compiler is giving you an error there but this really *should* work IMO.


P.S. Ah never mind ... I should learn to read posts before writing replies.
Quote:Original post by Red Ant
I don't know why the compiler is giving you an error there but this really *should* work IMO.


It doesn't because the shared_ptr constructor that takes a single pointer is explicit.
Yeah sorry ... I hadn't read the post properly before replying. I see now that he was relying on an implicit conversion.
Quote:Original post by fpsgamer
Quote:Original post by vtchill
Just to add to the above post, it is potentially dangerous to use an unnamed temporary shared_ptr as it has the potential to cause a memory leak.

Something like this would be a better alternative.

*** Source Snippet Removed ***


Actually it isn't a problem in that case. It would only be a problem if the function accepted multiple arguments.

reference


youch ... i never considered this. my code has a lot of this kind of thing, (the justification for the init() seperate from the constructor is for dealing with things that interact with shared_from_this())

class A{     typedef shared_ptr< A>  ptr;      static ptr create()      {         ptr p( new A);          p->init();           return p;      }};


is it safe to use in this type of context.

vector< A::ptr>    va; va.push_back( A::create() );


i think its ok - its still a temporary being returned that is used as the const arg of the push_back method, but both the shared pointer and underlying object have been fully constructed and use_count() is always positive even if its only being held by a temporary. what about multiple argument functions . if one of the other arguments methods throws on the constructor - would that still be memory safe ?
Quote:Original post by chairthrower
i think its ok - its still a temporary being returned that is used as the const arg of the push_back method, but both the shared pointer and underlying object have been fully constructed and use_count() is always positive even if its only being held by a temporary. what about multiple argument functions . if one of the other arguments methods throws on the constructor - would that still be memory safe ?


The scenario you illustrated is safe.

The problem (as you've already noted) has to do with when you are dealing with multiple arguments.

Consider this:

void doStuff(boost::shared_ptr<Foo>(new Foo()), Bar() );

The order in which arguments are evaluated in C++ is undefined. If an exception is thrown at inopportune times you will get a resource leak. Consider this hypothetical argument evaluation order:


(1) exectute 'new Foo()'
(2) construct temporary Bar() object
(3) construct shared_ptr<Foo> from the value returned by 'new Foo()'

If (2) two throws an exception, stack unwinding will commence and we will loose a handle to the memory allocated in (1).

Thats why you should do this instead:

boost::shared_ptr<Foo>ptr(new Foo());
void doStuff(ptr, Bar() );

If stack unwinding begins as the result of a thrown exception, the shared_ptr will be destroyed and take appropriate care of the heap resource.

Further Reading.

This topic is closed to new replies.

Advertisement