S foo ()
{
S s;
s.frob (1);
return s;
}
--
VH
NRVO yes, RVO no, IIUC.
Just an observation I'd like to share: Assuming frob returns "*this"
there's a difference between
s.frob (1);
return s;
and
return s.frob (1);
because the 2nd case probably disables NRVO unless the compiler
inlines the function and is smart enough to figure out that the
returned reference actually refers to 's'.
That's the reason why I usually write
T operator+(T const& a, T const& b)
{
T r = a;
r += b;
return r;
}
instead of
T operator+(T const& a, T const& b)
{
T r = a;
return r += b;
}
for some custom "arithmetic-like" type T.
Cheers!
SG
--
VH
No, just that it's named. A compiler implementing NRVO can, in
principle, elide copy constructing the return value whereas a compiler
implementing only RVO cannot (since the returned variable has a name).
Contrast this with something like return S( 1 ).
What's the difference between RVO and NRVO, besides the object having a name?
Nothing, really. In both cases, the compiler "merges" a local
object (named or a temporary) with the object it returns.
Logically, I would expect RVO to be simpler and more natural,
but I seem to recall hearing that it was, in fact, NRVO which
was implemented first.
Realistically, I would expect most compilers today to implement
both, regardless of the level of optimization requested. With
regards to being (N)RVO friendly: about the only thing you have
to avoid is multiple returns in the function (but good
programming practice bans those anyway). Basically, if the
expression in the return is simply the name of a local variable,
NRVO will be used, otherwise RVO. But the compiler can't apply
both in the same function, and it can't use NRVO on two
different local variables.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > are there any guide lines for writing (N)RVO friendly code?
> > E.g. is the following (N)RVO friendly?
> > S foo ()
> > {
> > S s;
> > s.frob (1);
> > return s;
> > }
> Just an observation I'd like to share: Assuming frob returns
> "*this" there's a difference between
> s.frob (1);
> return s;
> and
> return s.frob (1);
> because the 2nd case probably disables NRVO unless the
> compiler inlines the function and is smart enough to figure
> out that the returned reference actually refers to 's'.
NRVO really only applies when the expression in the return
statement is simply the name of a local non-static variable.
Otherwise, it's RVO. If S::frob() returns an S, the compiler
will probably arrange for this to be constructed (in S::frob)
directly in the return value of foo. If S::frob() returns an S&
or an S const&, of course, the object that it refers to will be
copied---the compiler can't know that it is the same object as s
(and I'm not sure that even if it did, I'm not sure that
removing the copy would be legal.
> That's the reason why I usually write
> T operator+(T const& a, T const& b)
> {
> T r = a;
> r += b;
> return r;
> }
> instead of
> T operator+(T const& a, T const& b)
> {
> T r = a;
> return r += b;
> }
> for some custom "arithmetic-like" type T.
The other alternative I've seen is:
T operator+(T const& a, T const& b)
{
return T(r) += b;
}
Personally, I don't like it, but supposedly, it allows RVO.
(Although if operator+= returns a T&, and isn't inlined, I don't
quite see how; in general, if all you have is a reference, and
you need an object, I think you need a copy. The reference
could, after all refer to an object with static lifetime.)
Anyway, your point concerning references (you didn't mention
them, but I presume that that's what you meant) is well taken.
An expression in the return statement which evaluates to a
reference will likely inhibit RVO (and of course, is it isn't
the name of a non-static local variable, NRVO doesn't come into
play). So the rules are: single return statement, whose
expression doesn't have reference type. And if the expression
is simply the name of a variable, the named variable is a
non-static local variable.