shared_ptr is to weak_ptr as unique_ptr is to... what?
There is a genuine need for a standard pointer type to act as a non-owning, inexpensive, and well-behaved counterpoint to std::unique_ptr<>
. No such pointer has been standardized yet, but a standard has been proposed and is under discussion by the C++ standards committee. The "World's Dumbest Smart Pointer", aka std::exempt_ptr<>
would have the general semantics of other modern C++ pointer classes but would hold no responsibility either for owning the pointed-to object (as shared_ptr
and unique_ptr
do) or for correctly responding to the deletion of that object (as weak_ptr
does).
Assuming that this feature is ultimately ratified by the committee, it would fully meet the need highlighted in this question. Even if it isn't ratified by the committee, the above linked document fully expresses the need and describes a complete solution.
std::unique_ptr vs std::shared_ptr vs std::weak_ptr vs std::auto_ptr vs raw pointers
what idiom is each smart pointer supposed to replace?
Every single one of them, ever, that eventually involved destroying the pointed-to resource. So in other words, virtually all of them. I can think of no idioms involving raw pointers that did not involve destroying a pointed-to resource. Every other use isn't really an idiom, it's just "Using a pointer".
Differences between unique_ptr and shared_ptr
Both of these classes are smart pointers, which means that they automatically (in most cases) will deallocate the object that they point at when that object can no longer be referenced. The difference between the two is how many different pointers of each type can refer to a resource.
When using unique_ptr
, there can be at most one unique_ptr
pointing at any one resource. When that unique_ptr
is destroyed, the resource is automatically reclaimed. Because there can only be one unique_ptr
to any resource, any attempt to make a copy of a unique_ptr
will cause a compile-time error. For example, this code is illegal:
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr
However, unique_ptr
can be moved using the new move semantics:
unique_ptr<T> myPtr(new T); // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr
Similarly, you can do something like this:
unique_ptr<T> MyFunction() {
unique_ptr<T> myPtr(/* ... */);
/* ... */
return myPtr;
}
This idiom means "I'm returning a managed resource to you. If you don't explicitly capture the return value, then the resource will be cleaned up. If you do, then you now have exclusive ownership of that resource." In this way, you can think of unique_ptr
as a safer, better replacement for auto_ptr
.
shared_ptr
, on the other hand, allows for multiple pointers to point at a given resource. When the very last shared_ptr
to a resource is destroyed, the resource will be deallocated. For example, this code is perfectly legal:
shared_ptr<T> myPtr(new T); // Okay
shared_ptr<T> myOtherPtr = myPtr; // Sure! Now have two pointers to the resource.
Internally, shared_ptr
uses reference counting to track how many pointers refer to a resource, so you need to be careful not to introduce any reference cycles.
In short:
- Use
unique_ptr
when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. - Use
shared_ptr
when you want multiple pointers to the same resource.
When is std::weak_ptr useful?
A good example would be a cache.
For recently accessed objects, you want to keep them in memory, so you hold a strong pointer to them. Periodically, you scan the cache and decide which objects have not been accessed recently. You don't need to keep those in memory, so you get rid of the strong pointer.
But what if that object is in use and some other code holds a strong pointer to it? If the cache gets rid of its only pointer to the object, it can never find it again. So the cache keeps a weak pointer to objects that it needs to find if they happen to stay in memory.
This is exactly what a weak pointer does -- it allows you to locate an object if it's still around, but doesn't keep it around if nothing else needs it.
shared_ptr Real life use-cases
In our simulator product, we use a framework to deliver messages between simulation components (called endpoints). These endpoints could reside on multiple threads within a process, or even on multiple machines in a simulation cluster with messages routed through a mesh of RDMA or TCP connections. The API looks roughly like:
class Endpoint {
public:
// Fill in sender address, etc., in msg, then send it to all
// subscribers on topic.
void send(std::unique_ptr<Message> msg, TopicId topic);
// Register this endpoint as a subscriber to topic, with handler
// called on receiving messages on that topic.
void subscribe(TopicId topic,
std::function<void(std::shared_ptr<const Message>)> handler);
};
In general, once the sender endpoint has executed send
, it does not need to wait for any response from any receiver. So, if we were to try to keep a single owner throughout the message routing process, it would not make sense to keep ownership in the caller of send
or otherwise, send
would have to wait until all receivers are done processing the message, which would introduce an unnecessary round trip delay. On the other hand, if multiple receivers are subscribed to the topic
, it also wouldn't make sense to assign unique ownership to any single one of them, as we don't know which one of them needs the message the longest. That would leave the routing infrastructure itself as the unique owner; but again, in that case, then the routing infrastructure would have to wait for all receivers to be done, while the infrastructure could have numerous messages to deliver to multiple threads, and it also wants to be able to pass off the message to receivers and be able to go to the next message to be delivered. Another alternative would be to keep a set of unique pointers to messages sent waiting for threads to process them, and have the receivers notify the message router when they're done; but that would also introduce unnecessary overhead.
On the other hand, by using shared_ptr
here, once the routing infrastructure is done delivering messages to incoming queues of the endpoints, it can then release ownership to be shared between the various receivers. Then, the thread-safe reference counting ensures that the Message
gets freed once all the receivers are done processing it. And in the case that there are subscribers on remote machines, the serialization and transmission component could be another shared owner of the message while it's doing its work; then, on the receiving machine(s), the receiving and deserialization component can pass off ownership of the Message
copy it creates to shared ownership of the receivers on that machine.
Cannot convert from std::shared_ptr_Ty to std::shared_ptr_Ty
You get that error because static_cast
requires the types from
and to
to be convertible. For shared_ptr
that will hold only if c'tor overload 9 would participate in overload resolution. But it doesn't, because void*
is not implicitly convertible to other object pointer types in C++, it needs an explicit static_cast
.
If you want to convert shared pointers based on static_casting
the managed pointer types, you need to use std::static_pointer_cast
, that is what it's for.
So after plugging that fix
std::shared_ptr<T> top() { return std::static_pointer_cast<T>(GenericStack::top()); }
Your thin template wrapper will build fine.
When to use shared_ptr and when to use raw pointers?
Your analysis is quite correct, I think. In this situation, I also would return a bare B*
, or even a [const] B&
if the object is guaranteed to never be null.
Having had some time to peruse smart pointers, I arrived at some guidelines which tell me what to do in many cases:
- If you return an object whose lifetime is to be managed by the caller, return
std::unique_ptr
. The caller can assign it to astd::shared_ptr
if it wants. - Returning
std::shared_ptr
is actually quite rare, and when it makes sense, it is generally obvious: you indicate to the caller that it will prolong the lifetime of the pointed-to object beyond the lifetime of the object which was originally maintaining the resource. Returning shared pointers from factories is no exception: you must do this eg. when you usestd::enable_shared_from_this
. - You very rarely need
std::weak_ptr
, except when you want to make sense of thelock
method. This has some uses, but they are rare. In your example, if the lifetime of theA
object was not deterministic from the caller's point of view, this would have been something to consider. - If you return a reference to an existing object whose lifetime the caller cannot control, then return a bare pointer or a reference. By doing so, you tell the caller that an object exists and that she doesn't have to take care of its lifetime. You should return a reference if you don't make use of the
nullptr
value.
libc++ doesn't allow construction of shared_ptrT from unique_ptrT[]
The standard (pre-C++17) only says the following about the 13th constructor:
This constructor shall not participate in overload resolution unless
unique_ptr<Y, D>::pointer
is convertible toT*
.
But since std::unique_ptr<int[]>::pointer
is convertible to int*
the code should work. It's a bug in libc++.
In the meantime you can use the following:
auto sp = std::shared_ptr<int>(up.release(), up.get_deleter());
Related Topics
Clean Eclipse Index, It Is Out of Sync with Code
When Does Move Constructor Get Called
C++ Metafunction to Determine Whether a Type Is Callable
C++11 Anonymous Union with Non-Trivial Members
Boost-Python How to Pass a C++ Class Instance to a Python Class
Access Private Member Using Template Trick
Who Defines C Operator Precedence and Associativity
Should the Copy-And-Swap Idiom Become the Copy-And-Move Idiom in C++11
What Should I Know About Structured Exceptions (Seh) in C++
Debug Assertion Failed! Expression: _Acrt_First_Block == Header
What Is the Size of an Enum Type Data in C++
Project Error: Unknown Module(S) in Qt: Webkitwidgets