来源: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 2ps->i = 8;return ps; // should be freed later
}int main() {S s; // 1. default ctor 1get_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 1if (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 2S s = get_D1();// 触发RVO
S s1 = get_D2(); // 不触发RVO 拷贝构造