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
On the other hand when using make_shared
both the tracked object and the reference counting can be allocated together.
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_ptr
s 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_ptr
s that will outlive your pointed to object and you need your memory back ASAP consider not using make_shared
.
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.
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.
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.
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.
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.
[…] Make_shared, almost a silver bullet | I will not buy this blog, it is scratched!. […]
[…] make_shared只分配一次内存, 这看起来很好. 减少了内存分配的开销. 问题来了,weak_ptr会保持控制块(强引用, 以及弱引用的信息)的生命周期, 而因此连带着保持了对象分配的内存, 只有最后一个weak_ptr离开作用域时, 内存才会被释放. 原本强引用减为0时就可以释放的内存, 现在变为了强引用, 若引用都减为0时才能释放, 意外的延迟了内存释放的时间. 这对于内存要求高的场景来说, 是一个需要注意的问题. 关于这个问题可以看这里make_shared, almost a silver bullet […]
[…] 2.Make_shared, almost a silver bullet […]
[…] Make_shared, almost a silver bullet […]