2

I've asked a couple questions (here and here) about memory management, and invariably someone suggests that I use boost::shared_ptrs.

Given how useful they seem to be, I'm seriously considering switching over my entire application to use boost::shared_ptrs.

However, before I jump in with both feet and do this, I wanted to ask -- Has anyone had any bad experiences with boost::shared_ptrs? Is there some pitfall to using them that I need to watch out for?

Right now, they seem almost too good to be true - taking care of most of my garbage collection concerns automatically. What's the downside?

Runcible
  • 7,006
  • 12
  • 42
  • 62

4 Answers4

4

The downside is they're not free. You especially shouldn't use shared_ptr/shared_array when scoped_ptr/scoped_array (or plain old stack allocation) will do. You'll need to manually break cycles with weak_ptr if you have any. The vector question you link to is one case where I might reach for a shared_ptr, the second question I would not. Not copying is a premature optimization, especially if the string class does it for you already. If the string class is reference counted, it will also be able to implement COW properly, which can't really be done with the shared_ptr<string> approach. Using shared_ptr willy-nilly will also introduce "interface friction" with external libraries/apis.

Logan Capaldo
  • 39,555
  • 5
  • 63
  • 78
  • strings don't usually use COW. It doesn't play nicely with multithreaded apps, so most implementations dropped it again. Which means string copies are somewhat costly. – jalf Feb 26 '09 at 05:40
  • GCC's string implementation still uses COW IIRC. But with C++0x they will *likely* be disallowed (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2668.htm) - and good riddance. – Greg Rogers Feb 26 '09 at 14:22
2

Boost shared pointers or any other technique of memory management in C++ is not a panacea. There is no substitution for careful coding. If you dive into using boost::shared_ptr be aware of object ownership and avoid circular references. You are going to need to explicitly break cycles or use boost::weak_ptr where necessary.

Also be careful to always use boost::shared_ptr for an instance from the moment it is allocated. That way you are sure you won't have dangling references. One way you can ensure that is to use factory methods that return your newly created object in a shared_ptr.

typedef boost::shared_ptr<Widget> WidgetPtr;
WidgetPtr myWidget = Widget::Create();
m-sharp
  • 16,443
  • 1
  • 26
  • 26
1

I use shared_ptr's often.

Since Shared_ptr's are copied by-value, you can incur the cost of copying both the pointer value and a reference count, but if boost::intrusive_ptr is used, the reference count must be added to your class, and there is no additional overhead above that of using a raw pointer.

However, in my experience, more than 99% of the time, the overhead of copying boost::shared_ptr instances throughout your code is insignificant. Usually, as C. A. R. Hoare noted, premature optimization is pointless - most of the time other code will use significantly more time than the time to copy small objects. Your mileage may vary. If profiling show the copying is an issue, you can switch to intrusive pointers.

As already noted above, cycles must be broken by using a weak_ptr, or there will be a memory leak. This will happen with data structures such as some graphs, but if, for example, you are making a tree structure where the leaves never point backwards, you can just use shared_pointers for nodes of the tree without any issues.

Using shared_ptr's properly greatly simplifies code, makes it easier to read, and easier to maintain. In many cases using them is the right choice.

Of course, as already mentioned, in some cases, using scoped_ptr (or scoped_array) is the right choice. If the pointee isn't being shared, don't use shared pointers!

Finally, the most recent C++ standard provides the std::tr1::shared_ptr template, which is now on most platforms, although I don't think there is an intrusive pointer type for tr1 (or rather, there might be, but I have not heard of it myself).

Bill H
  • 96
  • 2
0

Dynamic memory overhead (i.e., extra allocations) plus all the overhead associated with reference counted smart pointers.

MSN
  • 53,214
  • 7
  • 75
  • 105