Polymorphism and boost::shared_ptr

Reposted from my old blog. Here’s the news from 2009…

I’m currently in the final stages of converting a library from raw pointers to boost::shared_ptr. I’m mainly doing this to ensure the correct pointer/pointee ownership rather than the outright prevention of memory leaks, but the latter is a nice side effect of the former.

One problem I ran into was that the library I’m updating and its clients make rather heavy use of polymorphism. Of course in 99% of the code that was fine as the objects were accessed through pointers to base classes, but the last 1% was causing problems because that part of the code contained lots of dynamic_cast statements. These classes unfortunately need to know the exact type they were dealing with so there was no easy way around the use of these idioms. It probably isn’t news to most of the people reading this blog that dynamic_cast and boost::shared_ptr don’t play that nicely.

The main issue is that taking a pointer that is held inside a boost::shared_ptr, dynamic_casting it down the hierarchy and then stuffing it into another boost::shared_ptr is a good way to ensure double deletion. Oops. So, if you see the following code you better get the debugger out…

 

   boost::shared_ptr<A> something(new A(blah));
   ...
   boost::shared_ptr<B> something_else(dynamic_cast<B>(something.get()));

 

So far so bad, but I couldn’t believe that something with a flaw that obvious would be in the boost libraries. And of course, there is a way around this – boost provides alternatives to the four C++ casts with similar names that work on boost::shared_ptrs. You can find these alternatives – which are really just wrappers around the C++ casts, but designed to work with the boost smart pointers – in the include file boost/pointer_cast.hpp.. If you’re using smart pointers because you need polymorphic behaviour of, say, items stored in standard C++ containers, have a look at this page right now. If you don’t have the time or inclination to check the linked document right now, the management summary is: “The next time someone tells you that you can’t use boost:.shared_ptr with dynamic_cast, point them in the direction of boost::dynamic_pointer_cast”. Using boost::dynamic_pointer_cast would change the above example to:

 

  

   boost::shared_ptr<A> something(new A(blah));
   ...
   boost::shared_ptr<B> something_else =
     boost::dynamic_pointer_cast<B>(something));

 

Problem solved.