Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

pre return optimization

0 views
Skip to first unread message

terminator(jam)

unread,
Oct 9, 2007, 11:56:13 AM10/9/07
to
consider:

struct memory_pig{//a really large type:

memory_pig(){
std::cout<<"mem pig default\n";
//etc...
};

memory_pig(memory_pig const&){
std::cout<<"mem pig copy\n";
//etc...
};

~memory_pig(){
std::cout<<"mem pig finish\n";
//etc...
};

//etc...

};///struct memory_pig

memory_pig foo(){
memory_pig result;
result=something;
//etc...
result=something_else;
return result;
};

any time 'foo' is called the output will contain the following
sequence:


mem pig default
mem pig copy
mem pig finish

the last line of output may repeat based on how the result is
stored(rvo) or not.
So,two objects of a large type will be constructed and at least one is
destructed on every call to 'foo' in PASCAL you can write:

function foo:memory_pig
begin
foo:=something;
{etc...}
foo:=somthing_else;
end

that is you can refrence the returned object inside the function and
decrease the overhead for copying large objects.C++ lacks such syntax
and IMHO we should be able to mark the result object as referencing
the actual return so that there is no need for the extra copy
construction;this is espesifically beneficall when dealing with
operator definitions .We can declare the return itself as an object.I
suggest the following syntax:

class ret_type funxn (paramlist){
ret_type return /*optional:*/(initiallizer params);

//etc...

if(false)return;//return like void functions

//return something;//error:named return accepts no param.

return=something;//ok;
return=something_else;
return.member_funxn();
another_funcxn(return);

};

Provided that 'return' is declared as an object { whenever you use the
'return' keyword inside pharantesis or accompanied via an operator ?
the return object is referenced :otherwise a parameterless 'return'
returns to the caller.
The return object is an lvalue inside the function and can be aliased
for readability:

memory_pig foo(){
memory_pig return , & result=return;
result=something;
//etc...
result=something_else;
};

and whenever 'foo' is called the output looks like this:

mem pig default

the unnessesary copy/move has vanished and the destruction of
temporary depends on what you do with it.

regards,
FM.

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

Greg Herlihy

unread,
Oct 14, 2007, 4:08:09 AM10/14/07
to

The C++ Standard already allows the "(Named) Return Value
Optimization" (NRVO or RVO for short). The optimization allows (under
certain conditions) the compiler to construct the result of a function
call "in place" - that is, directly in the object initialized with the
function call result.

So, to take advantage of this optimization, a program should use the
result of a function call to initialize an object, instead of
assigning the function result to an existing object.

For example:

#include <iostream>

using std::cout;

struct memory_pig
{ // a really large type:
memory_pig()
{


cout << "mem pig default\n";
}

memory_pig(memory_pig const&)
{


cout << "mem pig copy\n";
}

~memory_pig()
{


cout << "mem pig finish\n";
}

};

memory_pig foo()
{
memory_pig result;
// ...
return result;
}

int main()
{
memory_pig m1 = foo();
memory_pig m2 = foo();
memory_pig m3 = foo();
}

I compiled the above program twice, once with and once without NRVO.
The output of both programs is shown in the two columns below. As this
comparison shows, NRVO can be a particular effective optimization -
even for a small C++ program like the one used in this example.

Program Output

Without NRVO: With NRVO:

mem pig default mem pig default
mem pig copy mem pig default
mem pig finish mem pig default


mem pig copy mem pig finish

mem pig finish mem pig finish
mem pig default mem pig finish


mem pig copy
mem pig finish
mem pig copy
mem pig finish
mem pig default
mem pig copy
mem pig finish
mem pig copy
mem pig finish

mem pig finish
mem pig finish
mem pig finish

Greg

terminator

unread,
Oct 14, 2007, 3:19:28 PM10/14/07
to
I knew about RVO but not NRVO(that is what I am talking about).Is NRVO
standard behavoir or unspecified?
At least my compiler does not perform the NRVO.

thanx,
FM.

Erik Wikström

unread,
Oct 14, 2007, 3:00:39 PM10/14/07
to

>>


> I knew about RVO but not NRVO(that is what I am talking about).Is NRVO
> standard behavoir or unspecified?
> At least my compiler does not perform the NRVO.

The standard allows this optimisation, but it does not require it (see
section 12.8 paragraph 15). I think that most newer compilers support
it, but you might have to turn up the optimisation level a bit.

One important thing to remember is that when NRVO is in use the
destructor will not be called for the local object, nor will the copy-
constructor for the non-local object (m1 to m3 in the code above) be
called. Thus you should not depend on any side effects that the copy-
constructor or destructor might have.

--
Erik Wikström

terminator(jam)

unread,
Oct 15, 2007, 11:52:49 AM10/15/07
to

prior to return and after return are two different case to me:I mean
before return even move should be disabled ,while after the return
either of move/copy must perform .

regards,
FM.

Erik Wikström

unread,
Oct 15, 2007, 1:35:18 PM10/15/07
to

===================================== MODERATOR'S COMMENT:

Please trim unnecessary material when replying.


===================================== END OF MODERATOR'S COMMENT

Sorry, but you lost me there, what move? Of what to where?

--
Erik Wikström

int...@gmail.com

unread,
Oct 16, 2007, 1:44:30 AM10/16/07
to

It won't. It certainly won't do that with the example given, since
there's no clear association in it between the copy constructor and
the assignment operator (considering that the latter isn't even
defined). Assuming there was such an association, though, I'd rather
expect to see:

mem pig default
mem pig copy // first assignment
mem pig copy // second assignment
mem pig finish

Which is correct and fine - if you have explicitly written the
assignment operator twice, then surely you want the associated side-
effects? And if you do not, then perhaps you shouldn't have written it
that way.

> that is you can refrence the returned object inside the function and
> decrease the overhead for copying large objects.C++ lacks such syntax
> and IMHO we should be able to mark the result object as referencing
> the actual return so that there is no need for the extra copy
> construction

This is precisely what NRVO does.

I have a feeling that you're confusing assignment with initialization
in this case. Assignment operator always applies to an already-
initialized object - the compiler cannot elide the initialization
except for the trivial cases (e.g. POD types), which is why operator=
still results in unnecessary copying even when the compiler implements
NRVO. It's not a problem with NRVO though - it's because assignment is
used where just initialization would suffice. Direct initialization is
still more efficient then assignment-following-initialization, even
with the move semantics of C++0x.

terminator(jam)

unread,
Oct 16, 2007, 1:55:54 PM10/16/07
to

Move ctor of course.

regards,
FM.

terminator(jam)

unread,
Oct 16, 2007, 3:26:48 PM10/16/07
to
As I wrote before its just an illustration and I did not mean any
assignment,replace it with any function( eg. modify(result) ;).

> Which is correct and fine - if you have explicitly written the
> assignment operator twice, then surely you want the associated side-
> effects? And if you do not, then perhaps you shouldn't have written it
> that way.
>
> > that is you can refrence the returned object inside the function and
> > decrease the overhead for copying large objects.C++ lacks such syntax
> > and IMHO we should be able to mark the result object as referencing
> > the actual return so that there is no need for the extra copy
> > construction
>
> This is precisely what NRVO does.
>

I was certain about the NRVO by the time I started the post.However
NRVO is a compiler option(ugly!!!) not a demand .With NRVO we have two
distinct phases optimize simultaniously : prior to return inside the
callee and after that inside the caller:

A foo(){
A ret;//this will be return under any conditions.
//....
return ret;//pre return :no copy/move
};
class A a=foo();//after return : copy/move to a


> I have a feeling that you're confusing assignment with initialization
> in this case. Assignment operator always applies to an already-
> initialized object - the compiler cannot elide the initialization
> except for the trivial cases (e.g. POD types), which is why operator=
> still results in unnecessary copying even when the compiler implements
> NRVO. It's not a problem with NRVO though - it's because assignment is
> used where just initialization would suffice. Direct initialization is
> still more efficient then assignment-following-initialization, even
> with the move semantics of C++0x.

Everybody makes mistakes while learning , but confusing assignment
with copy certainly has never been the mistake I can make.

regards,
FM

Erik Wikström

unread,
Oct 16, 2007, 2:37:25 PM10/16/07
to

Sorry, but I still do not understand. What do you mean with RNVO should
be disabled before return but not after? It is something that is
performed *during* return.

--
Erik Wikström

terminator(jam)

unread,
Oct 17, 2007, 11:53:24 AM10/17/07
to

I mean the whole concept of optimization(rvo,nrvo,etc). IMHO:
If a function always returns the same local object the returned object
must be the local object itself rather than a copy/move version of the
local.
If a function returns one of its parameter values returned object is
copy/moved from that parameter because a change in location of the
object is almost inevitable.
If an object is constructed with an rvalue it should be copy/moved.

regards,
FM

int...@gmail.com

unread,
Oct 17, 2007, 1:53:54 PM10/17/07
to
On 16 Oct, 23:26, "terminator(jam)" <farid.mehr...@gmail.com> wrote:
> A foo(){
> A ret;//this will be return under any conditions.
> //....
> return ret;//pre return :no copy/move};
>
> class A a=foo();//after return : copy/move to a

This is not the case. If the compiler correctly implements NRVO, the
example above will result in a single construction of A using the
default constructor, and then a subsequent destruction. No copies or
moves are made at any point.

Erik Wikström

unread,
Oct 17, 2007, 1:13:28 PM10/17/07
to

You mean for a function such as

foo bar()
{
foo f;
return f;
}

NRVO should be used? That is (to my knowledge) the case if NRVO is
enabled in the compiler.

> rather than a copy/move version of the local.

What is the difference between copy and move? I would say that NRVO is
move, since the object created in the function is moved to the
"surrounding" context/scope instead of being used as the basis of a copy.

> If a function returns one of its parameter values returned object is
> copy/moved from that parameter because a change in location of the
> object is almost inevitable.

Assuming that you by copy/move mean that the object in the function is
being copied to the surrounding scope, did you mean that something like

foo bar(bool b)
{
foo f1, f2;
if (b)
return f1;
else
return f2;
}

should not use NRVO? Again, to my knowledge that is the case, since the
compiler can not predict which of the objects will be returned so a copy
is necessary.

> If an object is constructed with an rvalue it should be copy/moved.

You mean something similar to

foo bar()
{
foo f1, f2;
return f1 + f2;
}

In that case NRVO could be used depending on whether the compiler knows
which object will be returned or not. So the above could utilise NRVO
but something like

foo bar(bool b)
{
foo f1, f2, f3;
if (b)
return f1 + f2;
else
return f2 + f3;
}

could not.

If the above is not what you meant, then I am sorry to have failed to
understand you. Perhaps you could try to rephrase the question or use
simple code examples.

--
Erik Wikström

0 new messages