Question

I have spend a few hours about rvalue s and lvalue. Here is what I understand

int main()
{
  //.....
  Foo foo = Bar1();
  foo = Bar2();
  //......
}  

Foo Bar1()
{
  //Do something including create foo
  return foo;
}

Foo& Bar2()
{
  //Do something including create foo
  return foo;
}

Under c++03, Bar1() would copy the return object (just before return), and then return the address of the copied object; executing a wasteful copy of an object which is about to be destroyed. Bar2() would return the object created within the function.

Under c++11, Bar1() and Bar2() would essentially be equivalent (and also equivalent to Bar2() of c++03).

Is that right? If not, please elaborate.

Was it helpful?

Solution 2

The concept of rvalues and lvalues didn't change from older C++ to C++11. What you describe as "C++03" is what should happen. Some compiler optimizations in some cases can reduce the number of unnecessary copies (including unnecessary copy-constructor calls!), but otherwise it is the same.

What did change is that C++11 introduced a concept of rvalue-reference (T&&).

There are several articles on it that you can google up, for example over here:

http://thbecker.net/articles/rvalue_references/section_01.html

OTHER TIPS

They are not the same. Bar2() is UB by both standards. You cannot return object created on stack by reference.

In C++03 Bar1() may take advantage of RVO and nothing will be copied. In C++11 Bar1() will even use RVO or will use a move constructor if RVO is not possible.

Bar2() doesn't create any copy in either C++ 2003 or C++ 2011. For Bar1() a copy of foo is created in both C++ 2003 and C++ 2011. The use of rvalue references only applies when you actually do have an rvalue or if you have an lvalue which is about to go away and it is being returned.

Of course, the example happens to be undefined behavior because the foo being return is the foo being initialized. That is, it seems you example is messed up by not stating what foo is meant to be when it is returned. Assuming each function has a local variable foo, Bar2() is undefined behavior according to both standards and Bar1() is somewhat different:

  • If there is a move constructor for Foo, C++ 2011 may use the move constructor while C++ 2003 may use the copy constructor.
  • Whether either the move constructor or the copy constructor is used depends on the rest of the function and the compiler: If all return statements in Bar1() return foo, construction of an extra object will be elided by most compilers.

Bar2() would return the object created within the function.

That's plainly wrong. Bar2() would return reference to some object. (Note: it would be UB if object is created on stack inside Bar2()).

Under c++11, Bar1() and Bar2() would essentially be equivalent (and also equivalent to Bar2() of c++03).

Under C++11 meaning would the same. What you really interested in is a move semantics:

Foo Bar3()
{
  //Do something
  return std::move(foo);
}

This would not execute a copy constructor, but a move constructor - which should be much less resource hungry.

This article may be interesting for you: Want Speed? Pass by Value.

In C++03, Bar1() may copy the object (but this is optimized away with to the so called copy elision -- see link).

In C++11, essentially nothing has changed. The compiler is allowed to either call Foo's copy constructor or Foo's move constructor or do copy elision. But since even in C++03 the copy would be elided, Bar1() does the same in C++11 and C++03.

Bar2() return just a reference, there is nothing different in C++11. Returning references is can be critical. If foo would be a local value, a reference to a already destroyed variable is returned, never to this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top