Why can't a weak_ptr be constructed from a unique_ptr?
If you think about it, a weak_ptr
must refer to something other than the object itself. That's because the object can cease to exist (when there are no more strong pointers to it) and the weak_ptr
still has to refer to something that contains the information that the object no longer exists.
With a shared_ptr
, that something is the thing that contains the reference count. But with a unique_ptr
, there is no reference count, so there is no thing that contains the reference count, thus nothing to continue to exist when the object is gone. So there's nothing for a weak_ptr
to refer to.
There would also be no sane way to use such a weak_ptr
. To use it, you'd have to have some way to guarantee that the object wasn't destroyed while you were using it. That's easy with a shared_ptr
-- that's what a shared_ptr
does. But how do you do that with a unique_ptr
? You obviously can't have two of them, and something else must already own the object or it would have been destroyed since your pointer is weak.
std::weak_ptr
can't be used unless you convert it to std::shared_ptr
by the means of lock()
. if the standard allowed what you suggest, that means that you need to convert std::weak_ptr to unique in order to use it, violating the uniqueness (or re-inventing std::shared_ptr
)
In order to illustrate, look at the two pieces of code:
std::shared_ptr<int> shared = std::make_shared<int>(10);
std::weak_ptr<int> weak(shared);
{
*(weak.lock()) = 20; //OK, the temporary shared_ptr will be destroyed but the pointee-integer still has shared to keep it alive
}
Now with your suggestion:
std::unique_ptr<int> unique = std::make_unique<int>(10);
std::weak_ptr<int> weak(unique);
{
*(weak.lock()) = 20; //not OK. the temporary unique_ptr will be destroyed but unique still points at it!
}
That has been said, you may suggest that there is only one unique_ptr
, and you still can dereference weak_ptr
(without creating another unique_ptr
) then there is no problem. But then what is the difference between unique_ptr
and shared_ptr
with one reference? or moreover, what is the difference between a regular unique_ptr
and C-pointers an get by using get
?
weak_ptr
is not for "general nonowning resources", it has a very specific job - The main goal of weak_ptr
is to prevent circular pointing of shared_ptr
which will make a memory leak. Anything else needs to be done with plain unique_ptr
and shared_ptr
.
A shared_ptr
basically has two parts:
- the pointed-to object
- the reference count object
Once the reference count drops to zero the object (#1) is deleted.
Now a weak_ptr
needs to be able to know if an object still exists. In order to do this it has to be able to see the reference count object (#2) if it's not zero it can create a shared_ptr
for the object (by incrementing the reference count). If the count is zero it will return an empty shared_ptr
.
Now consider when the reference count object (#2) can be deleted? We must wait till no shared_ptr
OR weak_ptr
object refer to it. For this purpose the reference count object holds two reference counts, a strong ref and a weak ref. The reference count object will only be deleted when both its counts are zero. This means that part of the memory can only be freed after all the weak references are gone (this implies a hidden disadvantage with make_shared
).
tl;dr; weak_ptr
depends on a weak reference count which is part of shared_ptr
, there cannot be a weak_ptr
without a shared_ptr
.