weak_ptr
?Section: 20.3.2.3.2 [util.smartptr.weak.const] Status: C++23 Submitter: Casey Carter Opened: 2019-03-15 Last modified: 2023-11-22
Priority: 2
View all issues with C++23 status.
Discussion:
20.3.2.3.2 [util.smartptr.weak.const] specifies weak_ptr
's default constructor:
constexpr weak_ptr() noexcept;1 Effects: Constructs an empty
2 Ensures:weak_ptr
object.use_count() == 0
.
and shared_ptr
converting constructor template:
weak_ptr(const weak_ptr& r) noexcept; template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept; template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;3 Remarks: The second and third constructors shall not participate in overload resolution unless
4 Effects: IfY*
is compatible withT*
.r
is empty, constructs an emptyweak_ptr
object; otherwise, constructs aweak_ptr
object that shares ownership withr
and stores a copy of the pointer stored inr
. 5 Ensures:use_count() == r.use_count()
.
Note that neither specifies the value of the stored pointer when the resulting weak_ptr
is empty.
This didn't matter — the stored pointer value was unobservable for an empty weak_ptr
—
until we added atomic<weak_ptr>
. 32.5.8.7.3 [util.smartptr.atomic.weak]/15 says:
Remarks: Two
weak_ptr
objects are equivalent if they store the same pointer value and either share ownership, or both are empty. The weak form may fail spuriously. See 32.5.8.2 [atomics.types.operations].
Two empty weak_ptr
objects that store different pointer values are not equivalent. We could
correct this by changing 32.5.8.7.3 [util.smartptr.atomic.weak]/15 to "Two weak_ptr
objects are
equivalent if they are both empty, or if they share ownership and store the same pointer value." In practice,
an implementation of atomic<weak_ptr>
will CAS on both the ownership (control block pointer)
and stored pointer value, so it seems cleaner to pin down the stored pointer value of an empty weak_ptr
.
[2019-06-09 Priority set to 2 after reflector discussion]
Previous resolution [SUPERSEDED]
This wording is relative to N4810.
Modify 20.3.2.3.2 [util.smartptr.weak.const] as indicated (note the drive-by edit to cleanup the occurrences of "constructs an object of class foo"):
constexpr weak_ptr() noexcept;-1- Effects: Constructs an empty
-2- Ensures:object that stores a null pointer value.weak_ptr
use_count() == 0
.weak_ptr(const weak_ptr& r) noexcept; template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept; template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;-3- Remarks: The second and third constructors shall not participate in overload resolution unless
-4- Effects: IfY*
is compatible withT*
.r
is empty, constructs an emptyobject that stores a null pointer value; otherwise, constructs aweak_ptr
weak_ptr
object that shares ownership withr
and stores a copy of the pointer stored inr
. -5- Ensures:use_count() == r.use_count()
.
[2020-02-14 Casey updates P/R per LWG instruction]
While reviewing the P/R in Prague, Tim Song noticed that the stored pointer value of a moved-fromweak_ptr
must also be specified.
[2020-02-16; Prague]
Reviewed revised wording and moved to Ready for Varna.
[2020-11-09 Approved In November virtual meeting. Status changed: Ready → WP.]
Proposed resolution:
This wording is relative to N4849.
Modify 20.3.2.3.2 [util.smartptr.weak.const] as indicated:
constexpr weak_ptr() noexcept;-1- Effects: Constructs an empty
-2- Postconditions:weak_ptr
object that stores a null pointer value.use_count() == 0
.weak_ptr(const weak_ptr& r) noexcept; template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept; template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;-3- Remarks: The second and third constructors shall not participate in overload resolution unless
-4- Effects: IfY*
is compatible withT*
.r
is empty, constructs an emptyweak_ptr
object that stores a null pointer value; otherwise, constructs aweak_ptr
object that shares ownership withr
and stores a copy of the pointer stored inr
. -5- Postconditions:use_count() == r.use_count()
.weak_ptr(weak_ptr&& r) noexcept; template<class Y> weak_ptr(weak_ptr<Y>&& r) noexcept;-6- Remarks: The second constructor shall not participate in overload resolution unless
-7- Effects: Move constructs aY*
is compatible withT*
.weak_ptr
instance fromr
. -8- Postconditions:*this
shall containcontains the old value ofr
.r
shall beis empty., stores a null pointer value, andr.use_count() == 0
.