My understanding is that in C++11, when you return a local variable from a function by value, the compiler is allowed to treat that variable as an r-value reference and 'move' it out of the function to return it (if RVO/NRVO doesn't happen instead, of course).
My question is, can't this break existing code?
Consider the following code:
#include <iostream>
#include <string>
struct bar
{
bar(const std::string& str) : _str(str) {}
bar(const bar&) = delete;
bar(bar&& other) : _str(std::move(other._str)) {other._str = "Stolen";}
void print() {std::cout << _str << std::endl;}
std::string _str;
};
struct foo
{
foo(bar& b) : _b(b) {}
~foo() {_b.print();}
bar& _b;
};
bar foobar()
{
bar b("Hello, World!");
foo f(b);
return std::move(b);
}
int main()
{
foobar();
return EXIT_SUCCESS;
}
My thoughts were that it would be possible for a destructor of a local object to reference the object that gets implicitly moved, and therefore unexpectedly see an 'empty' object. I tried to test this (see http://ideone.com/ZURoeT ), but I got the 'correct' result without the explicit std::move
in foobar()
. I'm guessing that was due to NRVO, but I didn't try to rearrange the code to disable that.
Am I correct in that this transformation (causing a move out of the function) happens implicitly and could break existing code?
UPDATE Here is an example which illustrates what I'm talking about. The following two links are for the same code. http://ideone.com/4GFIRu - C++03 http://ideone.com/FcL2Xj - C++11
If you look at the output, it's different.
So, I guess this question now becomes, was this considered when adding implicit move to the standard, and it was decided that it was OK to add this breaking change as this kind of code is rare enough? I also wonder if any compilers will warn in cases like this...