How does creating a reference to an rvalue work?

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
#include <iostream>

struct Test
{
	int data;
	Test() : data(0) { std::cout << "Default" << std::endl; }
	Test(const Test &from) : data(from.data) { std::cout << "Copy" << std::endl; }
	Test(int from) : data(from) { std::cout << "From" << std::endl; }
	Test &operator=(const Test &from){ data = from.data; std::cout << "Assignment" << std::endl; }
	~Test(){ std::cout << "Destructor" << std::endl; }
};

Test Func()
{
	Test t;
	t.data = 7;
	return t;
}

int main()
{
	Test &t = Func();
	std::cout << t.data << std::endl;
}

struct kr{~kr(){std::cin.ignore();}}k_r;
Default
Copy
Destructor
7
Destructor
Can someone explain what is going on with this code? I want to know if it is any more efficient to use a reference instead of copying the temporary. I heard someone on these forums say you can use a reference to extend the lifetime of a temporary, but I am confused by the output...
Test &t = Func(); This doesn't even compile. It has to be a reference to a const:
const Test &t = Func();

On line 15 the default constructor is used to initialize the object t.
When t is returned a temporary object is created by using the copy constructor. t's destructor is called because the function ends.
When the reference is bound to the temporary object it will not be destructed until the reference goes out of scope.

When I run your program I get the following output:
Default
7
Destructor

The difference is probably because of compiler optimizations. I don't think using a reference or copy the object in this case will do much difference on a modern compiler but I'm not sure.
Last edited on
Peter87 wrote:
This doesn't even compile.
Stupid VC++2008...

Well, I don't need to modify the temporary in this case so I'll use const. Though there have been times where I have needed to modify the temporary...

Thanks for the explanation.
> Well, I don't need to modify the temporary in this case so I'll use const.
> Though there have been times where I have needed to modify the temporary...

In C++98, I would just write:
1
2
Test t = Func() ;
t.data += 7 ;

and expect a decent compiler to apply copy elision. http://en.wikipedia.org/wiki/Copy_elision

C++11 has r-value references; for example, this is possible (without a copy being made):
1
2
3
4
Test&& rvr = Func() ;
rvr.data += 7 ;
extern std::vector< std::pair<Test, int > > myvector ;
myvector.emplace_back( rvr, 999 ) ;



JLBorges, thanks for that info :) I'm excited to find a good C++11 compiler. I think my current compiler supports that optimization though, so I'm not in a hurry just yet...
Last edited on
> I'm excited to find a good C++11 compiler.

As far as C++11 conformance goes, g++ is way ahead of the rest of the pack. Since you are on windows, a recent MinGw-GCC snapshot (if one so fancies, hooked up to an IDE like CodeBlocks or CodeLite) would be the best option as of now.

If you don't fancy building it from source, there are binary downloads. For example,
http://code.google.com/p/mingw-builds/downloads/detail?name=mingw32-gcc-4.7.0-snapshot-20120203-c%2Cc%2B%2B%2Cfortran-sjlj.7z




I don't think that rvalue reference would make a difference here. All that it ensures here is that the temporary object will be move constructed instead of copy constructed which makes no difference in this case.
Last edited on
Topic archived. No new replies allowed.