C++ Logo

std-proposals

Advanced search

Re: [std-proposals] When does vector::push_back() invalidation happen?

From: Avi Kivity <avi_at_[hidden]>
Date: Tue, 02 Apr 2024 17:49:34 +0300
On Sun, 2024-03-31 at 18:47 +0000, Jonathan Wakely wrote:
>
>
> On Sun, 31 Mar 2024 at 19:38, Jonathan Wakely <cxx_at_[hidden]> wrote:
> >
> >
> > On Sun, 31 Mar 2024, 18:51 Avi Kivity, <avi_at_[hidden]> wrote:
> > > On Sun, 2024-03-31 at 18:28 +0100, Jonathan Wakely via Std-
> > > Proposals wrote:
> > > >
> > > >
> > > > On Sun, 31 Mar 2024, 16:52 Thiago Macieira via Std-Proposals,
> > > > <std-proposals_at_[hidden]> wrote:
> > > > > On Sunday, 31 March 2024 08:22:05 PDT Avi Kivity via Std-
> > > > > Proposals wrote:
> > > > > > If it
> > > > > > reallocates after the push_back(), and the move constructor
> > > > > can throw,
> > > > > > then we lose the strong exception guarantee.
> > > > >
> > > > > It's impossible to reallocate after, because the vector must
> > > > > create space to
> > > > > store the new element. It can't store the element where
> > > > > there's no room.
> > > > >
> > > > > > The standard says:
> > > > > > > Remarks: Causes reallocation if the new size is greater
> > > > > than the old
> > > > > >
> > > > > > capacity. Reallocation invalidates all the references,
> > > > > pointers, and
> > > > > > iterators referring to the elements in the sequence, as
> > > > > well as the
> > > > > > past-the-end iterator.
> > > > > >
> > > > > > So, it says nothing about whether a push_back referring to
> > > > > a vector
> > > > > > element is legal.
> > > > > >
> > > > > > Is this undefined behavior? Should it be specified to work?
> > > > > Should it
> > > > > > be noted that it is dangerous?
> > > > >
> > > > > Looks pretty clear to me: if the new size is going to be
> > > > > bigger than the
> > > > > previous capacity, then it invalidates and therefore the
> > > > > reference stored by
> > > > > binding the parameter to v.back() is dangling. It's clearly
> > > > > UB to dereference
> > > > > it and therefore not expected to work.
> > > >
> > > > No, it's guaranteed to work. v.push_back(std::move(v.back()))
> > > > doesn't have to work, but Avi's example does. The standard says
> > > > the argument is pushed back, it doesn't say "unless it aliases
> > > > the container".
> > > >
> > > > This has been well understood and thoroughly tested by
> > > > implementers for decades.
> > > >
> > > >
> > >
> > >
> > >
> > > Yes, it was reported to me that libstdc++'s std::vector works.
> > >
> > > But, it's not clear from the wording. I'm sure that if the move
> > > constructor accesses the vector (via some side channel) it won't
> > > work.
> >
> > That's undefined, you can't access the vector reentrantly. While
> > the push_back call is actively modifying the container, another
> > call to it is undefined.
> >
> > We try to say this in https://eel.is/c++draft/reentrancy but we
> > completely fail to specify anything clearly. There's been an open
> > library issue about this for years.
> >
>
>
> That's https://cplusplus.github.io/LWG/issue2414
>
>
> And https://cplusplus.github.io/LWG/issue2164 is relevant to your
> push_back question, clarifying that it has to work even for emplace.
>
> And https://cplusplus.github.io/LWG/issue2382 is kinda relevant to
> both.
>


My head spins. Shouldn't the language prevent us from mutating a
parameter we're reading from? /runs


Received on 2024-04-02 14:49:42