Topic: NRVO (Was: no subject)


Author: "michael" <serrano@ozemail.com.au>
Date: 2000/08/21
Raw View
> The two syntactic oprions I've mentioned so far are:
>
> Foo f( void ) return val; // gcc, or
> void f( return Foo& val ); // the actual implementaion prototype

How about member initializer list style:

// foward declaration:
Foo F(int);

// implementation:
Foo F(int a) : return val
{
}

// or choose which ever of Foo's ctors we you want:
Foo F(int a) : return val (a)
{
    if (a < 0) val++; // whatever, just fall out the end.
}

IMO this conforms with the conception that F is a Foo contructor.

After all, I can currently guarantee no temporary by implementing F as a
subclass:

struct F : Foo
{
    F(int a) : Foo (a) {};
};

Seems like an artificial distinction to me...
[also consider this:.
    F().someFooMemberFunction();

    Now if F() is a ctor, then Foo does not need an accessible copy-ctor.
    But if F() is a function, then Foo must have an accessible copy-ctor.]






---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: normvcr@my-deja.com
Date: 2000/08/11
Raw View
In article <slrn8ou5pb.gca.qrczak@qrnik.knm.org.pl>,
  qrczak@knm.org.pl (Marcin 'Qrczak' Kowalczyk) wrote:
> Mon,  7 Aug 2000 16:52:07 GMT, Norman Goldstein <normvcr@istar.ca>
pisze:
>
> > That's a good point to cover.  My opinion is that if the elimination
> > of a copy consturctor breaks the program logic, then the copy
> > constructor is not well designed; having side effects, however,
does
> > not necesserally imply that a copy constructor cannot be safely &
> > correctly elliminated.
>
> The situation is worse. In
>     x =3D f (y, x);
> it's not easy to eliminate the temporary. If f constructs an object to
> return from the first argument and then accesses the second argument,
> then x is already lost.
>

I don't know what the "3D" is in your equation, but the point is
well taken.  This is another reason for adoping an explicit syntax
for RVO, so that the programmer can deal with this issue, rather than
(inadvertantly) sluffing it off to the compiler.




Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Norman Goldstein <normvcr@istar.ca>
Date: 2000/08/07
Raw View
(This thread has bounced between comp.std.c++ and comp.lang.c++ .  I'd
like to get it back to comp.std.c++ ... thanks.)

John Potter wrote:

> On 29 Jul 2000 16:47:55 -0400, Norman Goldstein <normvcr@istar.ca>
> wrote:
>
> > This note gathers together the information addressed in
> > the previous exchanges of this thread, and focusses on
> > the reason for my starting this thread in the first place.
> >
> > The purpose of this note is to ellicit feedback on extending C++ to
> > allow a form of RVO (return value optimization) that is more general

> > than that described in 12.8p15 of the ANSI/ISO Standard.  If the
> > optimization is deemed to be unsuitable, I would like to
> > understand why (a good learning experience).
> >
> > The Standard allows for the following statement to be optimized:
> >
> > Foo x = f();
> >
> > by constructing x directly, without the use of a temporary, provided

> > that f has a prototype like
> >
> > Foo f( void );
> >
> > gcc does exactly that, provided you use a language extension
> > particular to gcc.
>
> NO!  The statement Foo x = f(); is semantically identical to Foo
x(f());
> because the rhs expression has the same type as the lhs.  X is direct
> constructed from the return value of f.  There are many compilers
other
> than gcc which remove the temporary return value and gcc requires no
> extension to do this.  Consider:
>
>    Foo f () { Foo t(someInitializer()); modify(t); return t; }
>    Foo x(f());
>
> The semantics of the language say that a temporary copy of t is
> constructed to return, but this copy may be removed.  Test it and
> you will find that gcc and many other compilers will construct t
> and magically construct x from t without creating a temporary.
>
> There exist compilers which can also directly initialize x from
> someInitializer() without constructing t.  Gcc can not handle
> that; so, it has a kludge extension to allow it.

OK, suppose we have one of the few compilers that is able to
eliminate both temporaries from "Foo x = f()" without any
syntatctical aid.  There still remain the following cases to deal
with:

1.  Child x = f();
3.  The assignment operator= .  All the issues for the constructor
    can be carried over to this situation.

The spec does not discuss full optimization in these situations.  It
is the extension of the "optimizations" to these situations that
I would like to explore, now.

As I mentioned in my previous email, in situation 1, both
temporaries can be elliminated from Child x = f() by vieing f as
void f( Foo& val ) .  The temporaries cannot be eliminated by
viewing f as Foo f( void ); in fact the statement makes no sense
unless Child has a special "copy" constructor taking a Foo as a
parameter.

One could simply allow compilers to optimize in this
additional way, too.  But, then, previously non-compilable code
would become compilable, which is probably not a good thing.
This is another reason for introducing a syntax that simplifies
and guarantees the optimizaton process, rather than requiring
compilation gymnastics.

The two syntactic oprions I've mentioned so far are:

Foo f( void ) return val; // gcc, or
void f( return Foo& val ); // the actual implementaion prototype

> Before trying to change the language to gain some optimization, please

> research deja for the many complaints about the current rules.

Where in deja, please?  I have read through the ARM and D&E, and
have scanned the DRs (which aren't intended for extensions of the
language).

> The
> language says that a temporary is created and then says that it is
> ok to not do it.  It is the only optimization which may be detected
> by a conforming program.  There are many who do not like that at all
> because they would like to write programs which depend upon side
> effects of copy constructors.
>

That's a good point to cover.  My opinion is that if the elimination of
a
copy consturctor breaks the program logic, then the copy constructor
is not well designed; having side effects, however,  does not
necesserally imply that
a copy constructor cannot be safely & correctly elliminated.


> Your justification that z = x + y is better than compute(z, x, y) is
> of little value.  Try z = (a * x + b) * x + c.  With the current
> language rules I can write that as ((((z = a) *= x) += b) *= x) += c
> using no temporaries.  Will your syntactic sugar allow that?
>

I think you are missing my point.  Of course there are ways, with
the current syntax, to write efficient code.  Your example,
above, is an example of that, and has eliminated all temporaries.
Please note, though, that by writing (z = x) += y , the single
addition operator, z = x+y,  has been transformed into two sequential
operators.  If these are vector operands, for example, this
entails iterating through the vector components twice, rathen
than just once with z = x + y .  Moreover, my original point
also holds:  The syntax  z = x + y  is easier to read and
understand, and to relate to written mathematics.


> Also consider your thoughts in the context of multiple translation
> units where the call site can not see the implementation and the
> implementation can not see the use.
>

I'm sorry, I don't see the point you are making here.  The
declaration is all that is needed to call (use) a funtion.

In summary, the two opimations that I feel need to be addressed
are for  Child x = Foo(), and for operator=() .  They need to be
addressed in a way that eliminates _all_ temporaries.  The
current spec addresses only the case of construction, and for
an _exact_ match of the return type with the type of the object
being constrected (up to a const_cast).


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: qrczak@knm.org.pl (Marcin 'Qrczak' Kowalczyk)
Date: 2000/08/07
Raw View
Mon,  7 Aug 2000 16:52:07 GMT, Norman Goldstein <normvcr@istar.ca> pisze:

> That's a good point to cover.  My opinion is that if the elimination
> of a copy consturctor breaks the program logic, then the copy
> constructor is not well designed; having side effects, however,  does
> not necesserally imply that a copy constructor cannot be safely &
> correctly elliminated.

The situation is worse. In
    x =3D f (y, x);
it's not easy to eliminate the temporary. If f constructs an object to
return from the first argument and then accesses the second argument,
then x is already lost.

The ideal generic implementation of this expression would construct a
temporary and then _move_ it to x. But C++ among things like copying
constructor does not have moving, i.e. an operation that does the same
as assignment plus destructor of the original. It could be implemented
more efficiently, e.g. in a constant time for lists.

Alternatively, moving could be specified as construction plus
destruction of the original, assuming that the old x will get
destructed just before moving.

Moving would be enough to define a generic version of the assignment
operator (perhaps modulo exception issues, I don't know). OTOH it
is not expressible with standard constructs available now. memcpy
usually works, but not if there are some back-pointers.

It could be approximated with specialized std::swap, assuming that
default construction and destruction of the default value is cheap.

Alternatively classes could implement sharing of subcomponents with
garbage collection. Then temporaries are not bad. Qt does this.

--=20
 __("<  Marcin Kowalczyk * qrczak@knm.org.pl http://qrczak.ids.net.pl/
 \__/
  ^^                      SYGNATURA ZAST=CAPCZA
QRCZAK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: joerg.barfurth@attglobal.net (Joerg Barfurth)
Date: 2000/07/22
Raw View
Norman Goldstein <normvcr@istar.ca> wrote:

> It seems to me that the GNU C++ solution, below, is exactly
> what I am looking for.  More comments follow ...

I don't think so. All existing versions of NRVO _construct_ a return
value in place. None of them works for assigning to a preexisting
object; much less could the 'return object' be the base class part
of such a object and call polymorphic functions there.

> > > > Foo f(void) return r; // yes with ';'
> > > >  {
> > > >     r.var1=3D0;
> > > >  }
> > >
> > > I always found this annoying.

> I assume that the variable "r" is implicitly a reference to type "Foo".
> What is it that you find annoying about this notation/approach?

The effect of this can be reached if the compiler can do NRVO. The whole
idea of returning a value by falling off the end of the function or
using a return without arguments seems to be against the spirit of the
language. IMHO it may really hurt readability. And it may cause troubles
for maintenance.

> I don't like the idea of depending on the optimizer, or compiler
> cleverness, when one's exact
> intent can be achieved so clearly and succinctly.

Your intent is best served it seems, by using a parameter of type
modifiable reference to <Whatever>. This is very clear and succinct to
me

Also: This is more than an optimization, but it runs under that label..


> > >  Foo f(void)
> > >   {
> > >      Foo result;
> > >      result.var1=3D0;
> > >      return result;
> > >   }
> > >
> > > *as usual*. The compiler could check, whether result and the return
> > > type of f are the same, whether result is returned and whether
> nothing
> > > else is return. If any of these tests fail, it's business as usual.
> > > Otherwise, the variable could be removed by the optimizer.
> > >
>=20
> This doesn't work if the caller of f() is assigning the result to an
> object
> derived
> from Foo.  For example, the virtual function mechanism is bypassed.
>=20
> >
> > > This way one would get the best of both worlds: No extension to the
> > > languange _and_ optimal code.
> >
> > Indeed, the standard chose an even better option:
> > The compiler may optimize the above as stated _independent_
> > from the variable name.=20

> > This mechanism is called "named return value optimisation" (NRVO)

> > (note that g++'s extension was given the same name, since
> > it was invented before the standard used the name - a classic
> > naming conflict ;-))
> >
> > I don't know which compilers implement the std::NRVO
> > (maybe even g++ supports std::NRVO besides gcc::NRVO now).

> Would you please give a reference to std::NRVO ?  I checked the C++
> language standard, and there is no mention of it, there.

The std:: prefix is nonstandard here ;). It is used to distinguish it
from the g++ version - and the author explains that.

It means the right to elide an additional copy construction when
returning *a class object* from a function by value.=20

The Standard describes it in 12.8.15=20

--=20
J=F6rg Barfurth                         joerg.barfurth@attglobal.net
-------------- using std::disclaimer; -----------------------------
Download:     StarOffice 5.2 at       http://www.sun.com/staroffice
Participate:  OpenOffice now at       http://www.OpenOffice.org

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]