This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3195. What is the stored pointer value of an empty `weak_ptr`?

Section: 20.11.4.2 [util.smartptr.weak.const] Status: WP Submitter: Casey Carter Opened: 2019-03-15 Last modified: 2020-11-09

Priority: 2

View all issues with WP status.

Discussion:

20.11.4.2 [util.smartptr.weak.const] specifies `weak_ptr`'s default constructor:

>     constexpr weak_ptr() noexcept;

> > 1 Effects: Constructs an empty `weak_ptr` object.

> > 2 Ensures: `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 `Y*` is compatible with `T*`.

> > 4 Effects: If `r` is empty, constructs an empty `weak_ptr` object; otherwise, constructs a `weak_ptr` object that shares ownership with `r` and stores a copy of the pointer stored in `r`.

> > 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>`. 31.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 31.8.2 [atomics.types.operations].

Two empty `weak_ptr` objects that store different pointer values are not equivalent. We could correct this by changing 31.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.

> 1. Modify 20.11.4.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 `weak_ptr` object that stores a null pointer value.

>    > > -2- Ensures: `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 `Y*` is compatible with `T*`.

>    > > -4- Effects: If `r` is empty, constructs an empty `weak_ptr` object that stores a null pointer value; otherwise, constructs a `weak_ptr` object that shares ownership with `r` and stores a copy of the pointer stored in `r`.

>    > > -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-from `weak_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.

1. Modify 20.11.4.2 [util.smartptr.weak.const] as indicated:

   >     constexpr weak_ptr() noexcept;

   > > -1- Effects: Constructs an empty `weak_ptr` object that stores a null pointer value.

   > > -2- Postconditions: `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 `Y*` is compatible with `T*`.

   > > -4- Effects: If `r` is empty, constructs an empty `weak_ptr` object that stores a null pointer value; otherwise, constructs a `weak_ptr` object that shares ownership with `r` and stores a copy of the pointer stored in `r`.

   > > -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 `Y*` is compatible with `T*`.

   > > -7- Effects: Move constructs a `weak_ptr` instance from `r`.

   > > -8- Postconditions: `*this` shall contain contains the old value of `r`. `r` shall be is empty., stores a null pointer value, and `r.use_count() == 0`.