C++ Logo

std-proposals

Advanced search

Re: [std-proposals] ABI breaks

From: Avi Kivity <avi_at_[hidden]>
Date: Tue, 10 Jun 2025 13:33:34 +0300
On Mon, 2025-06-09 at 16:46 -0400, Arthur O'Dwyer wrote:
> On Mon, Jun 9, 2025 at 3:21 PM Avi Kivity via Std-Proposals <std-
> proposals_at_[hidden]> wrote:
> > [...]
> > Perhaps a different angle: just as we have
> > [[trivially_relocatable]] (move+destroy == memcpy), add
> > [[trivially_constructible]] and define it to memset(p, 0, sizeof).
> > This works for unique_ptr, the trivial types, std::string, many
> > others. User classes can use it to optimize unions and
> > implementations can choose whether to use it in std::optional or
> > not.
> >
>
>
> That's P2782 "is_trivially_value_initializable".


That's perfect and satisfies my needs.

> You can't use that trait in isolation, though; your `optional` would
> have to check that destroying, copying, moving, assigning... the
> value-initialized object doesn't have any side-effects either.
> I can't immediately think of a type where
> - `optional` could save a branch in, say, the assignment operator, in
> the way you propose; and yet
> - is_trivially_copyable<T> is false
> When is_trivially_copyable<T> is true, `optional` itself can be
> trivially copyable, so there's no branches to eliminate in that case
> anyway.


Consider std::indirect. It can be trivially value initialized.

std::optional's copy constructor, without the new optimization, and
after inlining, looks like

_engaged = other._engaged;
if (_engaged) {
     if (other._value) {
         _value = make an indirect copy of other._value
     }
}

With the new optimization:

_engaged = other._engaged;
if (other._value) {
     _value = make an indirect copy of other._value
}


std::optional has to assume that if it's trivially value initializable
then the non-trivial copy constructor would be cheap, buy that's a
reasonable assumption.


>
> Since you've mentioned [[trivially_relocatable]] twice now:
> (1) No, WG21 refuses to discuss P1144 [[trivially_relocatable]].
> They've shipped P2786 instead, which does not feature that attribute.


Okay, but it has the contextual keyword. I appreciate the correction,
but it doesn't materially change things.

> (2) Your earlier sketch of how `optional` could use trivial
> relocation seemed incomplete to me. It's true that if T is trivially
> relocatable [in the P1144 sense], then optional<T> can be trivially
> relocatable [in the P1144 sense]. It is also true that if T is
> trivially relocatable then optional<T> can be branchlessly move-
> assignable if you're willing to take an ABI break. But it is
> definitely not true that if T is trivially relocatable then
> optional<T> can be trivially move-assignable.


It's possible I made a mistake. But I'm sure the the ability to rely on
the presence of a constructed value, rather than having a conditionally
constructed value, can help std::optional (provided the vendor is
willing to take the ABI hit) or similar classes. For example, the move
constructor without the feature must conditionally destroy (or
conditionally swap?) this->_value, and can do it unconditionally with
the optimization.


> For more on both these points, see my recent blog posts
> https://quuxplusone.github.io/blog/2025/05/08/siren-song-2-optional/
> https://quuxplusone.github.io/blog/2025/05/09/siren-song-3-optional/


I'm afraid these go too deep for me. I did not track the parallel
evolution of competing trivial relocation proposals (I was vaguely
aware they existed), so it's hard for me to compare their details.

Received on 2025-06-10 10:33:39