来源:https://sigcpp.github.io/2020/06/08/return-value-optimization
简单总结:
函数返回值一般可以触发返回值复制优化,但是有下面几个条件:
- 语言支持。目前 GCC 和 MSVC 都默认执行 URVO,并且无法禁用它,因为 C++17 保证在返回临时对象时进行复制省略。
- 在接受函数返回值的语句是一个初始化语句(这样RVO才能发挥优势)
/// 触发
S get_name()
{
S s1;
return s1;
}
S get_uname()
{
return S();
}
S s = get_name(); /// 触发RVO
S s1 = get_uname(); /// 触发RVO
/// 不触发
S get_name()
{
S s1;
return s1;
}
S get_uname()
{
return S();
}
S s;
s = get_uname(); /// 失去优势,即使触发了RVO,这里也是assign。
可以通过传入引用的方式/指针用法 避免RVO失去优势
void get_F1(S& s) {
s.i = 8;
}
S* get_F2() {
S* ps = new S; // 2. default ctor 2
ps->i = 8;
return ps; // should be freed later
}
int main() {
S s; // 1. default ctor 1
get_F1(s);
std::cout << s.i << '\n';
S* ps{ get_F2() };
std::cout << ps->i << '\n';
delete ps; // 3. dtor 2
} // 4. dtor 1
- 函数本身不能从不同路径返回命名对象
/// 触发
S get_D1(int x) {
S s; // 1. default ctor 1
if (x % 2 == 0) {
s.i = 8;
return s;
} else {
s.i = 22;
return s;
}
}
/// 不触发 会引起拷贝构造
S get_D2(int x) {
if (x % 2 == 0) {
S s1; // 2. default ctor 2 (or default ctor for s2 below)
s1.i = 8;
return s1;
} else {
S s2; // 2. default ctor 2 (or default ctor for s1 above)
s2.i = 22;
return s2;
}
} // 3. copy ctor 3 (either s1 or s2 above); 4. dtor 2
S s = get_D1();// 触发RVO
S s1 = get_D2(); // 不触发RVO 拷贝构造