Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
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 - Fatal编程技术网

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++ 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

当然,这些函数在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.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

对于#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;
}