Passing by reference and RVO

Mar 15, 2011 at 12:32pm
Hi,

does passing a complex struct/class by reference always yield in better performance? IIRC, I read somewhere an counter example, where you get a worse performance (due to an unnecessary copy operation) when using "const Foobar&" instead of just "Foobar" as parameter value to a function. I think it was, if you have to copy the argument anyway.

But I can't find any references to this article anywhere...

Example reconstruction from mind:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>

struct Foobar
{ 
	// imagine some complex stuff and an inperformant copy constructor

	Foobar() {}
	Foobar(const Foobar& rv) { std::cout << "damn!\n"; }
};

struct Barfoo_byref
{
  Foobar f;
  Barfoo_byref(const Foobar& f_) : f(f_) {} // copies f_ all the time?
};

struct Barfoo_byvalue
{
  Foobar f;
  Barfoo_byvalue(Foobar f_) : f(f_) {} // may yield in no copy at all
};

Foobar foobarCreator() { return Foobar(); }

int main()
{
  Foobar f;
  std::cout << "rr\n";
  Barfoo_byref rr(f); // always has to copy, since f is on stack
  std::cout << "rv\n";
  Barfoo_byvalue rv(f); // ditto. Always has to copy. (Twice?)

  std::cout << "rrc\n";
  // always has to copy, because of "const Foobar&" ?
  Barfoo_byref rrc(foobarCreator());

  std::cout << "rvc\n";
  // may work without any copy because of RVO?
  Barfoo_byvalue rvc(foobarCreator());
}


Is this correct? Is return value optimization allowed to created the temporary object from the (probably inlined) foobarCreator directly at the place of Barfoo_byvalue's member?

I tried it with my compiler (VS2008) but it always copies (which doesn't mean anything..;).)


Ciao, Imi.
Last edited on Mar 15, 2011 at 12:37pm
Mar 15, 2011 at 12:39pm
I think it was, if you have to copy the argument anyway.

I am pretty sure this applies for cases in which the return value will be copied, not for cases in which the argument will be copied.

http://en.wikipedia.org/wiki/Return_value_optimization
Mar 15, 2011 at 1:15pm
You sound confused, unless I don't understand the question... Here goes:

I'm pretty sure that return value optimization only applies to functions that return something (by value). Lines 14 and 20 are copy constructors; they're not going to not copy. Line 23, however, is a candidate for RVO.

Last edited on Mar 15, 2011 at 1:15pm
Mar 15, 2011 at 1:20pm
There are too many restrictions on when the optimization can occur. Use const reference for now, and implement move constructors when you start using C++0x.
Mar 15, 2011 at 1:59pm
Ok, I may found the reference.

It isn't the special case of "return value optimization", but "copy elision", which is the name of the more general concept where compilers are allowed to skip copying of objects.


Wikipedia: http://en.wikipedia.org/wiki/Copy_elision

Interesting is the sentence "The optimization can not be applied to a temporary object that has been bound to a reference."


I am still not quite sure whether my example is a valid one. (And whether the temporary Foobar from "foobarCreator" can be created on the memory location of "Barfoo_byvalue" directly without any copy constructor call.)


Thanks hanst99, I already skimmed over the RVO article, but thanks to you, I now found the link to copy elision ;)

@moorecm: Yes, line 14 and 20 are copy constructors. Of course, *if* they are called, they *will* copy something ;). But they are not required to be called all the time. That's what RVO (and in general, elision) is about ;)

@PanGalactic: Yep, I know of the move semantic and std::move, but I am restricted to pre-C++0x for now and still want to save on copies. :)


And well... it doesn't matter whether I could theoretically save on copies, if my !"&// compiler don't implement it. I hope to figure out in which cases copies are avoidable and maybe I get some better result...

At the end of the day, I'll probably use this anyway:
1
2
3
4
createFoobar(Foobar* createMeHere) { ... }
...
Barfoo b();
createFoobar(&b.f);


;-)
Mar 15, 2011 at 2:37pm
It isn't the special case of "return value optimization", but "copy elision", which is the name of the more general concept where compilers are allowed to skip copying of objects.

Ahh... :P
Mar 15, 2011 at 6:34pm
I can not help myself, but to write something :) Well, I think I read somewhere that copy elision for function arguments was actually removed during the amendments in the 2003 version of the standard (vs 98 version.) And that the only way to make inline functions fully transparent at the moment is to pass the stuff by reference. Copy elision would still work in assignment initialization and in return value optimization.

By the way I don't presently know what the conditions for RVO are, but in practice there is a very simple technical reason for RVO. When you return big structures, the compiler passes them in a hidden output parameter, as if the caller allocated temporary object and passed it's address to the callee. Since the parameter is hidden, you can not construct the object inside it before returning from the function, which in some cases means that you wastefully create another object on the stack only to transfer its contents later in the hidden slot by copy constructor.

One approach to solve this is to make compiler extensions, like I think MS had some. But the standard has a gentler remedy, which basically says, create redundant objects, and we may construct them directly where the return value has to go, under certain conditions.

My personal advice, and I do not mean to enforce it. Use value arguments whenever you need to create temporaries afterward anyway. Use const references whenever you need only to observe properties and call const methods on the parameter, without actually producing new object. And remember - the compiler will do the right thing. If you pass something by reference, or even by pointer, it is unlikely that this reference or pointer is going to cause omnipresent indirection of access in the compiled code. I mean, do not bet on what compilers do. Just follow their recommendations tentatively.

Regards
Topic archived. No new replies allowed.