Let's consider these two functions :
// 1. Multiple returns of the same named object
string f() {
string s;
if (something())
return s.assign(get_value1());
else
return s.assign(get_value2());
}
and
// 2. Multiple returns, all of unnamed objects
string g() {
if (something())
return get_value1();
else
return get_value2();
}
How each of these functions will actually behave in terms of RVO is of course compiler-dependent. Am I right, however, to assume that RVO for both of them is common ?
p.s. (See answers) Function #1 was intended to be the following:
string f() {
string s;
if (something())
return s;
s.assign(get_value());
return s;
}
For #1, NRVO is guaranteed not to happen, that is, you're guaranteed to get a copy from s
to the return value of the function. In this case, you're better off doing
return std::move(s.assign(get_value1()));
Alternatively, if possible, rewrite the function to be NRVO-friendly:
string f() {
string s;
if (something())
s.assign(get_value1());
else
s.assign(get_value2());
return s;
}
Before the compiler even considers NRVO, several Standard requirements have to be met. The one that is not satisfied here is that the expression in the return
statement has to be the name of a variable. s.assign(...)
is not a name, it is a more complicated expression; you need to have something like return s;
for NRVO to be considered.
For #2, assuming the get_value
functions return string
(or const string
), you will most likely have RVO on any modern compiler, and, if all goes well with the ratification of C++17, RVO will be guaranteed in C++17 mode in any conformant compiler (still no guarantees for NRVO).
You can find very good and comprehensive information about (N)RVO (called copy elision in the Standard) on cppreference.com.
I decided to check the current compiler status, so I did some tests on GCC 6.1.0, Clang 3.8.0 and MSVC 2015 Update 3.
For #2, you do get RVO from all three compilers (prvalues in the return
statements are easy enough to analyze).
You also get NRVO from all three compilers for a construct like the "NRVO-friendly" one above (for MSVC, you need to have optimizations enabled).
However, for a function like
string f() {
string s;
if (something())
return s;
s.assign(get_value());
return s;
}
GCC and Clang do NRVO, but MSVC doesn't; it does however generate moves from s
to the return value, which is Standard conforming.
For another example:
string f() {
string s;
if (something())
return get_value1();
if (something_else())
return get_value2();
s.assign(get_value3());
return s;
}
All three compilers do RVO for the first two return
s and a move from s
for the third one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With