Compare with: std::shared_ptr which is empty but not null
The std::shared_ptr<T>
aliasing constructor lets us play interesting games. The above SO post discusses when the first argument is std::shared_ptr<void>{nullptr}
. I'm interested in the reverse. Is this guaranteed to keep the pointed-to object alive even though the shared_ptr
"is" nullptr
(and would be completely unreachable if it weren't that we keep a reference to it)?:
std::shared_ptr<S> ps = std::make_shared<S>();
auto& s = *ps; // Keep a reference to the S.
auto p = std::shared_ptr<S>(ps, nullptr); // Aliasing c'tor with null pointer.
ps = nullptr;
assert(ps == nullptr);
assert(p == nullptr);
foo(s); //< Is the S still alive here?
Yes, the "null but not empty" shared_ptr
will keep the object alive because it shares ownership with the shared_ptr
it was constructed from. All shared_ptr
s that share ownership with each other contribute to an atomic reference count stored in the control block, and only when this reference count hits zero is the owned object destroyed.
For standardese, see [util.smartptr.shared.const]/14:
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
Constructs ashared_ptr
instance that storesp
and shares ownership withr
There are no constraints specified on the value of p
; it may therefore be any valid pointer value, including null or even a past-the-end pointer (though I'm not sure why you'd want to do this).
Then see [util.smartptr.shared.dest]/(1.1):
If
*this
is empty or shares ownership with anothershared_ptr
instance (use_count() > 1
), there are no side effects.
In other words, when ps
is destroyed, it still shares ownership with p
, so the object is not destroyed yet.
The resulting object is not really unreachable in the usual sense, since it is still possible to destroy it. You just can't do anything else with it.