views:

290

answers:

3

It's been a while I coded in C/C++, and now I need its efficiency for a project I'm doing.

What I understand from this shared_ptr is that it basically deletes the object when I need it to. So, if, for example, my object has a vector of shared_ptr, I wouldn't have to worry about iterating through the vector and deleting each element in the destructor? In other words, I don't have to worry about memory management as long as I use these? Or am I totally misunderstanding this? It sounds too good to be true.

+8  A: 

You have to understand that shared pointers are implemented using a reference count, that means that if you have cycles in your pointer graph then the objects will not be released. That is, if a points to b and b points to a but nothing points to a or b, then neither a nor b will be released because they both have a reference count of '1'.

Boost provides weak pointers to get around this, which allows you to store a pointer to a shared object without incrementing its reference count. Weak pointers provide a layer of safety in that attempting to dereference the pointer after the shared pointer has been released will raise an exception rather than crashing the program.

Shared pointers are also quite expensive (at least compared to a raw pointer) in performance terms - but it's better to use them and then remove them once a profiler identifies a bottleneck rather than not use them everywhere.

Other than that, yes, they are very useful for managing dynamically allocated objects.

Edit: Another gotcha (that's mentioned on the boost pages) is to avoid "temporary" shared_pointers:

func(A(), boost::shared_ptr<B>(new B));

because the compiler is allowed to optimise this as

tmp1 = new B;
tmp2 = A();
tmp3 = boost::shared_ptr<B>(tmp1)
func(tmp2,tmp3)

which might look OK on first glance, but if A() happens to throw an exception then B has been allocated, but the shared_ptr hasn't gotten a hold of it yet, so the pointer never gets released.

Adam Bowen
+1 for mentioning cyclic references. Also, don't forget that they ease writing exception-safe code.
AraK
Technically correct answer, but it skips over the problem that in coding in this way, you'll lose out on the effiency that was the OP's motivation for using C++ in the first place.
jalf
But then you can always optimise out the shared pointers that are causing you the problem in your time critical code. It's much better to do it that way around than the other.
Adam Bowen
Also, I think performance is ancillary to the actual question - another programmer moving to C++ might have the same memory management concerns. I do agree that just coding in C++ may well not give you any performance benefit.
Adam Bowen
+5  A: 

You can do this but it's generally a bad idea. For a start you may lose some or all of the efficiency that you think you might be gaining.

More importantly, it sounds like you are trying to avoid designing your code. Java has gc, so you don't have to worry about memory management but you should still be concerned about object lifetimes. If you are not clear about who owns what you are likely to end up with a muddled design.

C++ gives you a lot of options when it comes to object lifetimes, not every complex object needs to be allocated on the heap. shared_ptr should be used for objects that require shared ownership (as it's name implies) but this should be a positive design decision. There are better ways to own an object if shared or transferable ownership aren't required.

Charles Bailey
+2  A: 

Here http://stackoverflow.com/questions/2079450/is-there-a-boostsharedptrt-equivalent-in-c I posted some information about different automatic memory management strategies. It explains main differences between GC and reference counting.

Only few modern C++ developers use such things like manual memory (or resource) management. Most of us use RAII idiom instead (see http://en.wikipedia.org/wiki/RAII), i.e. some utility classes that helps us to deal with resources.

Shared_ptr - is a great technique that facilitates routine memory/resource management tasks. This technique has some drawbacks (can't deal with cyclic structures, and it has performance overhead in both time and space. For every operation on references the implementation will now execute an arithmetic operation — and, in the detachment case, a conditional instruction. In addition, every object must be extended with an extra field to hold the count).

I recently participating in pretty large project (only my part contains more than 2 hundred classes) and I never (NEVER) use operator delete manually. Such utilities facilitates coding, debuging, maintenance, and significally reduces development costs. Lately I participating in similar project (with very similar business logic and architecture) but in C#. And I can tell you truly: they very much alike (first of all, because automatic memory management in C++ project).

P.S. Not every C++ programmer knew, but shared_ptr can use in automatic resource management (not only in automatic memory management) with custom deleter.

Sergey Teplyakov
+1 for custom deleter. They're nice for implementing RAII on resources coming from a C API. Boost barely documents that feature.
Emile Cormier