C++ C++;返回值优化,多个未命名返回 我们考虑这两个函数: // 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()); }
及 当然,这些函数在RVO方面的实际行为取决于编译器。然而,我是否正确地认为它们的RVO都是常见的C++ C++;返回值优化,多个未命名返回 我们考虑这两个函数: // 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()); },c++,rvo,C++,Rvo,及 当然,这些函数在RVO方面的实际行为取决于编译器。然而,我是否正确地认为它们的RVO都是常见的 p、 s.(见答案)功能#1的用途如下: string f() { string s; if (something()) return s; s.assign(get_value()); return s; } 对于#1,NRVO保证不会发生,也就是说,保证从s获取函数返回值的副本。在这种情况下,你最好这样做 return std::move(s
p、 s.(见答案)功能#1的用途如下:
string f() {
string s;
if (something())
return s;
s.assign(get_value());
return s;
}
对于#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(…)
不是一个名称,它是一个更复杂的表达式;您需要像returns待考虑的NRVO代码>
对于#2,假设get_value
函数返回string
(或const string
),您很可能在任何现代编译器上都有RVO,并且,如果C++17得到批准,RVO将在任何符合条件的编译器中以C++17模式得到保证(仍然没有对NRVO的保证)
您可以在上找到关于(N)RVO(在标准中称为复制省略)的非常好和全面的信息
我决定检查当前的编译器状态,所以我在GCC 6.1.0、Clang 3.8.0和MSVC 2015 Update 3上做了一些测试
对于#2,您确实可以从所有三个编译器获得RVO(return
语句中的PR值很容易分析)
对于上面的“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;
}
所有三个编译器对前两个进行RVO,并返回s,对第三个s
进行移动。谢谢您的回复。我确实认为get\u值
是对字符串
的求值。在压缩示例时,我感到有些紧张,我对#1的意思实际上更像是string s;if(sthg()){returns;}s.assign(get_value());返回s代码>。这仍然是一个提醒,如果我粗心,“抄袭省略”就不会发生。由于我的问题主要集中在第二个案例上,我将其标记为已解决,不再进行进一步编辑。@n.caillou该构造确实勾选了所有关于复制省略标准要求的框,看起来您确实从GCC和Clang获得了NRVO,但不是从MSVC获得的(2015年更新3)-具有相同变量名的多个return语句仍然会混淆它。但是,它会生成从s
到符合标准的返回值的移动。如果MSVC在您的例子中很重要,那么最好重写函数,以便在一个地方返回returns代码>。多个返回get_值()代码>对于所有三个编译器都很好-prvalues对于编译器来说更容易分析。经过再三考虑,我想我会将此注释移到答案中。我想知道最好的方法是什么,如果我想返回一个包含另一个容器的对,比如std::pair foo(){std::vector vec=(/*一些有用的东西*/);return std::make_pair(vec,42);}
?如果我理解正确,std::pair可能会发生复制省略,因为返回的语句是一个无名的临时语句,但向量会发生什么情况?@yussuf将从vec
复制到pair
的第一个成员中,从make\u pair
返回,因此返回std::make\u pair(std::move(vec),42)代码>会更好。对于vector
s,移动相对便宜,因此在实践中,可能不值得再麻烦了。如果您可以更改函数的结构,并且绝对希望避免任何复制或移动(可能您有一个std::array
而不是vector
),那么您可以使用容器构造一个局部pair
变量,对容器成员执行操作,并返回命名的pair变量。
string f() {
string s;
if (something())
return get_value1();
if (something_else())
return get_value2();
s.assign(get_value3());
return s;
}