让我们考虑这两个函数:
// 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());
}和
// 2. Multiple returns, all of unnamed objects
string g() {
if (something())
return get_value1();
else
return get_value2();
}每个函数在RVO方面的实际行为当然是依赖于编译器的。然而,我是否正确地认为,RVO对两者都是常见的呢?
附注:(见答案)函数#1的目的是:
string f() {
string s;
if (something())
return s;
s.assign(get_value());
return s;
}发布于 2016-07-11 20:39:45
对于#1,NRVO保证不会发生,也就是说,您保证从s获得一个副本到函数的返回值。在这种情况下,你最好还是
return std::move(s.assign(get_value1()));或者,如果可能的话,重写该函数使其对NRVO友好:
string f() {
string s;
if (something())
s.assign(get_value1());
else
s.assign(get_value2());
return s;
}在编译器考虑NRVO之前,必须满足几个标准要求。这里不满意的是,return语句中的表达式必须是变量的名称。s.assign(...)不是一个名称,它是一个更复杂的表达式;为了考虑NRVO,您需要有类似于return s;的东西。
对于#2,假设get_value函数返回string (或const string),那么在任何现代编译器上都很可能有RVO,而且,如果所有这些都符合C++17的批准,那么RVO将在任何符合的编译器中以C++17模式得到保证(对于NRVO仍然没有任何保证)。
您可以在cppreference.com上找到关于(N)RVO (在标准中称为复制省略)的非常好和全面的信息。
我决定检查当前的编译器状态,所以我对GCC 6.1.0、Clang 3.8.0和MSVC 2015更新3进行了一些测试。
对于#2,您可以从所有三个编译器获得RVO ( return语句中的prvalue很容易分析)。
您还可以从所有三个编译器获得NRVO,其结构类似于上面的“NRVO友好”(对于MSVC,您需要启用优化)。
但是,对于这样的函数
string f() {
string s;
if (something())
return s;
s.assign(get_value());
return s;
}GCC和Clang做NRVO,但MSVC没有;但是它会生成从s到返回值的移动,这是标准一致性。
另一个例子是:
string f() {
string s;
if (something())
return get_value1();
if (something_else())
return get_value2();
s.assign(get_value3());
return s;
}所有三个编译器都对前两个return执行RVO操作,而对于第三个编译器则从s迁移到RVO。
https://stackoverflow.com/questions/38311297
复制相似问题