C++ Logo

std-proposals

Advanced search

Re: Guaranteed copy elision for named return values

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Fri, 3 Jan 2020 15:34:56 -0500
On Fri, Jan 3, 2020 at 2:17 PM Anton Zhilin via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hi! I've prepared a proposal (draft), which aims to provide guaranteed
> copy elision for common cases of local variables being returned from a
> function.
>
> The proposal link:
> https://gist.github.com/Anton3/594141354ff9625db0b85775799312c7
>

This proposal seems more realistic than your similarly motivated
"alias-expressions" proposal.

 [ *Note:* Either the variable is of a non-reference type or it is a
reference participating in lifetime extension. — *end note* ]

This is actually interesting and innovative as far as I know. No current
compiler performs copy-elision on local variables of lifetime-extended
reference type. As far as I can tell, the paper standard does not *permit*
copy-elision in such situations. (But those two statements are not
particularly correlated in real life. David Stone and I have been
mostly-independently working on harmonizing practice with specification in
these areas. See P0527, P1155, P1825 — P1825 subsumes the other two, and
has been adopted for C++2a. P1825 doesn't talk about the lifetime-extension
case.)

// https://godbolt.org/z/JrW848
Widget foo() noexcept;
Widget bar() {
    auto&& w = foo(); // lifetime-extended temporary
    return w; // no compiler implements copy-elision here
}

If you want to permit copy-elision on lifetime-extended variables, I think
you'll have to do some surgery on the existing wording. Weak consensus in
the #future-standard channel is that when
http://eel.is/c++draft/class.copy.elision#1.1 talks about "the name of a
non-volatile automatic object," you'd have to do some real mental
gymnastics to interpret that to include non-volatile automatic variables of
*reference* type which happen to refer to a lifetime-extended object.
(Especially if you mean to exclude variables of reference type which happen
to refer to automatic objects that *aren't* lifetime-extended.)

// https://godbolt.org/z/JrW848
Widget foo() noexcept;
Widget bar() {
    auto temp = foo();
    auto&& w = temp; // reference to automatic object of the correct type,
but not as a result of lifetime extension
    return w; // copy-elision here would be insane
}

I'm vaguely skeptical of your use of "potential scope." No particular
problem I can see, but I would bet money that there are problems I don't
see yet.

    Widget baz() {
        Widget one;
        if (rand()) return one;
        Widget two;
        return two;
    }

IIUC, your proposal mandates that `return two;` must use copy-elision (so
`two` must be constructed straight into the return slot), but `return one;`
may-or-may-not use copy-elision (which actually means that it cannot
possibly use copy-elision, because it must leave the return slot available
for `two`). Is that an accurate reading of your proposal's intent?

P1144 "relocation" is 100% unrelated to copy-elision. Copy-elision is a
core-language optimization that is done on a single object; trivial
relocation is a library-level optimization that is [normally] done on a
contiguous range of objects. If you don't have a contiguous range of
objects (like a vector reallocation), then performing trivial relocation *as
an optimization* probably doesn't buy you anything that you couldn't get
from a good optimizer and the "as-if rule." Returning a
std::unique_ptr<int> "by move" is totally fine; the optimizer will get it.
(The other benefit of P1144 is that sometimes programmers need to use
trivial relocation for actual API reasons, such as because some C API
requires it. Having the `std::is_trivially_relocatable` trait allows those
programmers to static_assert that what they're doing is actually safe.)

my $.02,
–Arthur

Received on 2020-01-03 14:37:41