I have a function that "builds" a structure to return:
struct stuff {
int a;
double b;
Foo c;
};
stuff generate_stuff() {
Foo c = generate_foo();
//do stuff to Foo, that changes Foo:
//...
return {1, 2.0, c}; //should this be return {1, 2.0, move(c)};?
}
Should I be moving c
out of the function? I realize that frequently, (N)RVO can build the object in place, however there might be times when this ISN'T the case. When can't (N)RVO be done, and thus, when should I move an object of a function?
Put another way, this is obviously going to be RVO of the temporary that is returned. The question becomes, will NRVO (named return value optimization) happen with c
? Will c
be constructed in place (at the call site of the function, inside the temporary stuff
structure), or will c
be constructed in the function, and then copied into the structure at the call site.
What your call to move(c)
does is not moving c out of the function, but moving it into the temporary struct that is returned from the function. The temporary return value should always benefit from RVO. However, I believe that the move/copy of c into the temporary cannot be optimized away, as c itself is not a temporary. So here the move version should always be at least as efficient as the copy version (Tested for a simple scenario with g++, clang++ and MVC++).
If you have to absolutely minimize the number of copy/move operations, then you could write
struct stuff {
int a;
double b;
Foo c;
};
stuff generate_stuff() {
stuff s{ 1, 2.0, generate_foo() };
//use s.c instead of c
//...
return s;
}
which would result in only a single construction of Foo and no copies/moves thanks to NRVO.
EDIT:
As @dyp pointed out in the comments to your question, the in-place construction of Stuff isn't actually a case of RVO, but required by the standard. Anyway, the important part is that the move/copy of c
cannot be elided so that using move
should never result in a performance penalty.