C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::shared_ptr resurrect

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Mon, 11 Dec 2023 20:05:58 +0000
On Mon, 11 Dec 2023, 17:22 Lénárd Szolnoki, <cpp_at_[hidden]> wrote:

> On Mon, 2023-12-11 at 14:54 +0000, Jonathan Wakely via Std-Proposals
> wrote:
> >
> >
> > On Mon, 11 Dec 2023 at 14:43, Andrey Semashev via Std-Proposals
> > <std-proposals_at_[hidden]> 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.
>
> I assume that's meant to be `sm2.use_count() == 1`.


Yes I corrected myself in a later reply.


Isn't `use_count()`
> a relaxed atomic load of the reference count? I don't think it is
> suitable for this use case (or almost any use case). AFAIK it's the
> same reason that `unique()` got deprecated.
>
> > Since moving from sm is a non-const operation, other threads can't do
> > anything with sm concurrently.
> >
> >
> >
>
>

Received on 2023-12-11 20:06:15