On Mon, 11 Dec 2023 at 14:43, Andrey Semashev via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On 12/11/23 15:00, Valentin Palade via Std-Proposals wrote:
> Hello Everyone,
>
> I would like your opinion on a small addition to the std::shared_ptr:
>
> bool std::shared_ptr::resurrect();
>
> with the following behavior:
>
>   * will atomically decrement the use counter and
>       o if use counter != 0 will reset the shared_ptr instance and
>         return false
>       o otherwise, increment the use counter, leave the shared_ptr
>         instance unchanged and return true (thus resurrecting the
>         shared_ptr instance).
>
> Usage scenario:
>
>   * producer creates a shared_ptr message to be sent to multiple
>     consumers - threads/actors/connections
>   * on consumers, we want to be able to return the shared_ptr message to
>     the producer (e.g. to be reused), once consumed by all.

Why can't you use use_count()? If it returns 1, your shared_ptr is the
last instance and you may reuse it, as if your proposed resurrect()
returned true.

Note that this is thread safe since use_count() == 1 means there are no
other threads that may concurrently modify the reference counter.

That's not true. If the same shared_ptr object is visible in other threads, they could make a copy of it and increase the refcount. That could happen between calling use_count() and reusing it, a TOCTTOU race. Making the copy and calling use_count() are both const members, so the standard says you're allowed to do that concurrently.

The proposed resurrect() function "solves" this by being a non-const member, so if another thread concurrently makes a copy of that object they have a data race and so UB. So they're not allowed to make that copy.

But another way to do the same is:

  std::shared_ptr<T> sm2(std::move(sm));
  if (sm2.use_count())

Here we have a new local object which we know is not visible to any other threads, so if its use_count() is 1 then this really is a unique reference. Since moving from sm is a non-const operation, other threads can't do anything with sm concurrently.