|
Boost : |
From: David Abrahams (dave_at_[hidden])
Date: 2002-10-22 15:14:26
Daniel Frey <d.frey_at_[hidden]> writes:
> On Tue, 22 Oct 2002 21:33:41 +0200, Andrei Alexandrescu wrote:
>
> > "Daniel Frey" <d.frey_at_[hidden]> wrote in message
> > news:ap470c$u81$1_at_main.gmane.org...
> >> URVO is preferable, yes. It works almost everywhere, but sometimes -
> >> like for operator+ - the URVO can't help, you need the NRVO.
> >
> > Why can't it help?
> >
> > T operator+(const T& lhs, const T& rhs) {
> > return T(lhs) += rhs;
> > }
>
> this is equivalent to:
>
> T operator+( const T& lhs, const T& rhs ) {
> return T( lhs ).operator+=( rhs );
> }
Not neccessarily. It's possible to implement += as a free
function. I'm not sure if that's relevant to your argument or just a
red herring.
> You return the result provided by operator+=. operator+= might be
> implemented in a different compile-unit. Even if it isn't and the compiler
> could figure out that operator+= returns *this (the temporary created
> above), it is not allowed to apply any optimization except
>
> a) it can guarantee that there are no observable side effects
>
> or
>
> b) the standard explicitly allows optimizations that needn't care about
> observable side effects (see §3.7.2/2 and §12.8/15).
>
> While a) is hard to figure out for a compiler and I haven't seen any
> compiler that implements it for non-trivial classes, b) is your only hope
> to eliminate the temporary. And 'return T(lhs)+=rhs;' only looks like a
> case for URVO, but it isn't. Try it out...
>
> >> In these cases I
> >> think it's essential to help the compiler:
> >>
> >> T f()
> >> {
> >> T nrv;
> >> // add your code here ...
> >> return nrv;
> >> }
> >
> > But an explicit move constructor such as:
> >
> > T f()
> > {
> > T nrv;
> > // add your code here ...
> > return T(nrv, move);
> > }
> >
> > /always/ transforms an lvalue into a temporary at a small cost. So the
> > idiom above works efficiently on compilers that do URVO or NRVO, while
> > your idiom works only on compilers that support NRVO (which I understand
> > are a subset of the former).
>
> If the compiler implements NRVO, it cannot be made any better - the
> temporary is simply eliminated completely. If the compiler doesn't
> implement the NRVO, Mojo may be the best pattern. As you can see from the
> patch to operators.hpp, boost can provide both. Maybe you want to add a
> Mojo-friendly implementation of the non-NRVO version? ;)
I don't know how well that works. You need to know that T implements
the appropriate constructor, which AFAICT isn't possible for a generic
function.
> > So I'd say for programmers who want to make their code efficient on more
> > platforms, the latter idiom is better. The disadvantage, of course, is
> > that T needs to implement that constructor.
>
> I still hadn't the time to look at Mojo II, but if you can use only ONE
> implementation, Mojo might be best for now. For the future, I think more
> and more compilers will implement the NRVO. (Personally I'd be very
> interested to hear about the VC++7, but for some reason no-one here seems
> to test it and tell us the result :o).
I offered to run any test program posted, but nobody gave me one to
try.
-- David Abrahams dave_at_[hidden] * http://www.boost-consulting.com Building C/C++ Extensions for Python: Dec 9-11, Austin, TX http://www.enthought.com/training/building_extensions.html
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk