C++ Logo

sg14

Advanced search

Re: Two papers to look at

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Mon, 12 Feb 2024 16:54:58 -0500
On Mon, Feb 12, 2024 at 4:30 PM Nicolas Fleury <nidoizo_at_[hidden]> wrote:

> Great feedback.
>
> Note that support of [[asserts_rvo]] on the declaration is important to
> me, as the point is to add as a guideline for functions returning by copy
> in huge productions, and being able to call a function with trust regarding
> no-copy without needing to look at its implementation. This is really the
> most important to me, this is the kind of information I would expect
> in Intellisense. I'm not personally interested in something per return
> statement, I see it as a contract with the caller even before a contract
> with the compiler. I'm not against supporting it on return statements, but
> that's not my need. Initially it was named [[no_copy]], I wonder if I
> should have stayed with that name if people focus on the individual RVOs
> inside the function.
>

Maybe an illuminating question would be: What do you think of these two
function signatures, in your context?
(Showing the function bodies for clarity; but my understanding is that you
claim to want something that applies the same whether the body is visible
to the user or not.)

  std::string striplast1(std::string original)
    { original.pop_back(); return original; } // no RVO

  std::string striplast2(const std::string& original)
    { std::string copy = original; copy.pop_back(); return copy; } // yes
RVO

`striplast1` definitely 100% cannot use RVO, because the parameter
`original` is allocated by the caller, not the callee (so it can't go into
the return slot).
`striplast2` certainly can use RVO, and in the real world *invariably does*
use RVO.
Still, `plusworld1` is expected to be faster than `striplast2`, because
`striplast2` makes an O(n) copy of the string's contents, while
`striplast1` doesn't.
And, just to confuse matters, `striplast1(s)` makes a copy of `s` *in the
caller*, while `striplast2(s)` doesn't; this is separate from anything to
do with the return value.

So, even ignoring all the technical details and just treating your
[[asserts_rvo]] attribute as a pure code-comment advertisement ("This
Function Uses RVO!") — how do you see it helping in this case? As a user,
would you prefer to see that advertisement attached to the slow
`striplast1` function, the fast `striplast2` function, both, or neither?


While I cannot speak for everyone in the gaming industry, the main thing to
> understand is that we're forced to see RVO as a pure bonus, since it's not
> guaranteed by contract when calling a function. We can live by still doing
> Foo(SomeClass&), but it can actually be more verbose to use. I'm looking
> for a way to benefit from RVO for the average programmer while not
> compromising performance because RVO is not made in a certain percentage of
> cases or code simply evolves.
>

A common pattern, if moves are cheap but copies are expensive, is to just
make your types move-only — and give them a .clone() or .copy() method as
an escape hatch for when you really explicitly need to make a copy. If your
moves are cheap, then you don't care about the difference between NRVO and
ordinary move-construction-into-the-return-slot. And if your moves *aren't*
cheap, then isn't that the much bigger problem?

–Arthur

>

Received on 2024-02-12 21:55:12