Reputation: 3099
Example:
struct s { int a; };
s func() { return {42}; }
int main() {
s new_obj = func(); // line 6
(void) new_obj;
return 0;
}
This works. Now, what happens, if we assume that our compiler does no RVO?
func
returns a struct of s
, so {42}
must be converted to s
, is then returned and finally copied to new_obj
in line 6.func
returns an initializer list, so a deep copy is impossible.What does the language say? Can you give a proof?
Note: I know that this does not seem useful in this example, but for returning very large, constant sized std::array
s, I do not want to rely on RVO.
Upvotes: 7
Views: 822
Reputation: 20533
Consider the following example:
#include <iostream>
struct foo {
foo(int) {}
foo(const foo&) { std::cout << "copy\n"; }
foo(foo&&) { std::cout << "move\n"; }
};
foo f() {
//return 42;
return { 42 };
}
int main() {
foo obj = f();
(void) obj;
}
When compiled with gcc 4.8.1 with -fno-elide-constructors
to prevent RVO the output is
move
If in f
the return statement without curly braces is used then, then the output is
move
move
With no RVO, what happens is the following. f
must create a temporary object of type foo
, let's call it ret
, to be returned.
If return { 42 };
is used, then ret
is direct initialized from the value 42
. So no copy/move constructor was called so far.
If return 42;
is used, then another temporary, let's call it tmp
is direct initialized from 42
and tmp
is moved to create ret
. Hence, one move constructor was called so far. (Notice that tmp
is an rvalue and foo
has a move constructor. If there was no move constructor, then the copy constructor would be called.)
Now ret
is an rvalue and is used to initialize obj
. Hence the move constuctor is called to move from ret
to obj
. (Again, in some circumstances, the copy constructor could be called instead.) Hence either one (for return { 42 };
) or two (for return 42;
) moves happen.
As I said in my comment to the OP's question, this post is very relevant: construction helper make_XYZ allowing RVO and type deduction even if XZY has noncopy constraint. Especially the excelent answer by R. Martinho Fernandes.
Upvotes: 5