Make_shared, almost a silver bullet

22 04 2012

Herb Sutter just published a new Guru of the Week in which he claims one should always use make_shared when created shared pointers.

This is very good advice (as one can expect from Herb) but I can’t resist the urge to nitpick.

As Herb states the advantage of using make_shared is that when you use plain new the shared_ptr object must allocate the reference counting block separately from the (existing) tracked object

Memory layout when using new

On the other hand when using make_shared both the tracked object and the reference counting can be allocated together.

Memory layout when using make_shared

This has the following advantages:

  • One less memory allocation (and deallocation), this is both faster and takes up less memory (the allocator overhead for size tracking)
  • Increased data locality, the ref counts and the object are probably in the same memory page (perhaps even the same cache line)

However there could be rare cases in which the make_shared implementation has a drawback. Consider what happens if we use weak_ptrs to break cycles in our ownership graph and the object’s strong references expire while some weak references hold on. This means that the pointed at object must be destroyed but we still need the reference counts (specifically the weak reference count).

So in the case where we used plain-old new we get:

void releaseStrongRef()
{
    if (--data_->strongRefs_ == 0)
        delete data_->value_; // destroy object and free its memory
    if (data_->weakRefs_ == 0)
        delete data_;
}

void releaseWeakRef()
{
    if (--data_->weakRefs_ == 0)
        delete data_;
}

While the make_shared implementation will have to hold on to the memory till the weak references are released:

void releaseStrongRef()
{
    if(--data_->strongRefs_ == 0) 
        data_->value_->~T();// explicitly destroy object, memory isn't freed
    if(data_->weakRefs_ == 0)
        delete data_;
}

void releaseWeakRef()
{
    if(--data_->weakRefs_ == 0)
        delete data_;
}

So if you’re expecting to use weak_ptrs that will outlive your pointed to object and you need your memory back ASAP consider not using make_shared.

Advertisements

Actions

Information

5 responses

23 04 2012
Waldemar Pawlaszek

Yes. It’s an old problem that e.g. emerged few time on stackoverflow and I’ve written about it in the question ( http://herbsutter.com/2012/01/20/gotw-103-smart-pointers-part-1-difficulty-310/#comment-4714 ). It isn’t obvious (it didn’t cross my mind when I’ve read about make_shared) and it should be pointed out explicitly when advocating consistent usage of make_shared. Fortunately Mr. Sutter did mention it.

Additionally there are many pitfalls in shared_ptr’s that might be painful to discover when you stumble upon it. For example enable_shared_from_this does not work well with multiple inheritance: try to create few classes each inherited from enable_shared_from_this and declare one derived class inherited from all of them, create an instance, cast it few times and see how each shared_from_this behaves.

23 04 2012
Motti Lanzkron

Do’h just when I thought I had an original thought 🙂

BTW where does Mr. Sutter mention the weak_ptr issue? I didn’t see it.

23 04 2012
Waldemar Pawlaszek

It’s not easy to find anything new in C++ world 🙂

Not directly, but it is mentioned in two bullets at the beginning of point 2 while defining “strong reference” (that the memory might be deallocated at the destruction of last of it) and “weak reference” (that it is deallocated at the destruction of last of it if it was not already). Although in my opinion little too-not-directly and it should have been noted explicitly.

25 04 2012
Puckering Pink Hexagon

Just FYI if you’re coming from Java, use of leading underscores (‘_blah’) anywhere is discouraged in C++, because it reduces portability. Besides global actual runtime/linktime symbols which could clash with the OS, I believe there’s danger from macros, meaning you’re not safe even using them as member vars (I could have sworn Herb Sutter wrote something about this in one or more of his books but I can’t find a reference to it). Here’s this, instead – http://bytes.com/topic/c/answers/171648-leading-underscore. Note that this goes further than the standard’s reserving /double/ leading underscores, and leading underscores followed by a capital letter. Regardless of whether you’ll ever use your code on obscure, badly-built OSes, it’s a bit annoying to the rest of us.

25 04 2012
Motti Lanzkron

You’re right, I’ve been coding too much C# recently :(, actually AFAIK leading underlines are only reserved for global or namespace level entities and should be OK in class members but I’ll change my sample code to trailing underscores anyway.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: