Boost logo

Boost :

From: Andrei Alexandrescu (andrewalex_at_[hidden])
Date: 2002-10-22 12:12:55


"Daniel Frey" <daniel.frey_at_[hidden]> wrote in message
news:3DB512AF.244AAC5_at_aixigo.de...
> 2. What most compilers actually do
>
> When generating code, most compilers do something like that:
>
> void Fun(void* __pResult)
> {
> new(__pResult) T(expression);
> }
>
> char __buf[sizeof(T)]; // assume proper alignment
> Fun(&__buf);
> T& obj = *reinterpret_cast<T*>(&__buf);
>
> As you see, there's a copy constructor there that takes expression as a
> source.

>The memory for the object that holds a function's result is provided by
the caller, while the construction of the object is done by the callee.
This was - at least for me - the most important thing to understand.
Almost everything else follows from this fact :)<

Just to eliminate any potential confusion on my part, I assume you merely
repeat in English what the code says.

>Given the two points above, it seems trivial to implement the RVO and
AFAIK most compilers get it right. Problematic are functions with
multiple return paths.<

For URVO multiple return paths are absolutely no problem. Whenever you
return a temporary, the compiler will simply create in-place the return
value. No unnecessary copying.

For NRVO indeed multiple returns are a problem.

>It's the same as the unnamed RVO - except that the object is created
earlier and it has a name.<

On the contrary, I'd say NRVO and URVO are very different as far as compiler
writing is concerned. For URVO all the compiler has to do is... nothing.
It's a supertrivial job. It would be more work to NOT do URVO. For NRVO the
compiler must scan the entire function for its exit points, figure out if
they refer to the same variable, and change the semantics of that stack
variable to allocate it at a specific address. That's no rocket science, but
it's not trivial, either.

At a point I recall gcc had a hint:

T Fun() __returns__(result)
{
    T result;
    ...
    return result;
}

so the user tells the compiler which local variable the code returns, so
that the compiler has an easier job doing NRVO. In contrast, URVO is very
trivial.

>Once a compiler has implemented this, it
seems to be pretty stable. The GCC (3.1+) applies the NRVO even when all
optimization flags are turned off. The Intel-compiler (6.0+?) has
implemented the NRVO, too - although it's a bit buggy.<

Your third statement kinda sorta contradicts the first :o).

>Multiple returns are indeed a problem, but it's usually possible to keep
that in mind and design functions to be (N)RVO-friendly.<

So if my understanding above is correct (and I have to say that your post
didn't give me any clue on whether that's the case or not), it's better to
return temporaries rather than named values, because URVO is likely to be
much more widespread and reliable than NRVO.

>We are now discussing the basics of Mojo, are we? :)<

No. Mojo (http://moderncppdesign.com/mojo) is *guaranteed* to work 100%
regardless of the presence of any form of RVO. One thing I don't like about
certain optimizations is that you can't count on them, and the compiler
doesn't give you cues when it fails to apply them.

>
  movable< A >& as_movable() {
    return *static_cast< movable< A > >( static_cast< void* >( this ) );
  }
<

That should be static_cast<movable< A >*>.

>
template<> movable< A > : public A {
  movable( const A& a ) : A( a ) {}
  movable( movable< A >& m ) : A( m ) {}
  movable( int a, int b, int c ) : A( a, b, c ) {}
};

movable< A > f() { return movable< A >( a, b, c ); }
int main() { A a = f(); }
<

This won't work (I discovered the hard way) because moveable doesn't have a
moveable(const moveable&). More about that in the mojo document...

Andrei

--
All new!  THE C++ Seminar: Oct. 28-30 in Vancouver, WA.
http://www.thecppseminar.com/

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk