C++ Logo

std-discussion

Advanced search

Re: On "transparently replaceable" in std::vector operations

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Tue, 27 Apr 2021 20:03:19 -0400
On Tue, Apr 27, 2021 at 11:02 AM Giuseppe D'Angelo via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> Hi,
>
> Suppose I have a `std::vector<X>` with sufficient extra capacity to
> insert new elements without reallocation.
>
> [vector.modifiers] says that inserting an element at position `p`
> invalidates all iterators, references and pointers from position `p`
> onwards.
>
> I'm wondering why there's such a requirement for pointers (and
> references), considering the paragraph about "transparently replaceable"
> objects in [basic.life]:
>
> > http://eel.is/c++draft/basic.life#8
>
>
> Couldn't that paragraph be used to guarantee that, in fact, pointers and
> references after a non-reallocating insertion are still valid, but they
> just refer to "other" objects in the vector -- depending on the their
> position? For instance, in:
>
> > X* ptr = v.data();
> >
> > v.insert(v.begin(), x);
> >
> > use(*ptr); // <--
>
> could the last line be perfectly valid (not even a launder() required),
> pointing to the newly inserted element?
>
> Of course the discussion can be generalized to erasure.

Let's sidestep the whole issue of object models and just think of it
from the perspective of a user. As far as I'm concerned, even if the
object model made it OK, it would still be a terrible idea.

A container contains a bunch of things. If you get a pointer to one of
those things, then perform some operation on the container, what does
your pointer point to?

Logically, if you have a pointer to a thing in the container, if that
thing is still in the container, your pointer should *still point to
it*, right? That would make sense, yes? You have a pointer to some
element, you inserted another element, and your pointer still points
to the element it pointed to.

>From the perspective of the average user, a pointer or reference is
not a fancy index into the container. It points at/references
something that is in the container. And that pointer/reference means
something to the user.

After all, if they meant "the third element", then they could just
keep an index instead of a pointer/reference, right?

So from this point of view, if you perform an operation on a container
that does not directly manipulate that element, there are only two
reasonable possible states of that pointer/reference: either it still
points at what it used to point at, or it is not valid.

If you want the behavior of an index, then just *get an index*. Then
it's clear to everyone what is actually going on. We shouldn't make
pointers/references into `vector` behave like indices. And code that
expects them to do so seems rather confused as to what it is actually
trying to do.

Plus, it's a lot less fragile to use an index when that's the behavior
you want. After all, the pointer/reference validity can only be
allowed if reallocation doesn't occur. Which is not (yet) a thing you
can guarantee. It's better to write code that can't accidentally be
broken.

Received on 2021-04-27 19:03:33