Writing (N)RVO friendly code.

V

Vaclav Haisman

Hi,
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;
}
 
S

SG

Hi,
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'.

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
 
V

Vaclav Haisman

Jeff Schwab wrote, On 1.4.2009 15:32:
NRVO yes, RVO no, IIUC.
Could you elabore? What makes it friendly? Is it that that the return value
is declared as the first variable in the function?
 
R

Rolf Magnus

Jeff said:
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?
 
J

James Kanze

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.
 
J

James Kanze

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,426
Latest member
MrMet

Latest Threads

Top