自动变量的复制省略用于返回

时间:2011-04-24 13:03:13

标签: c++ c++11 rvalue-reference return-value-optimization copy-elision

我想知道是否在C ++ 0x “12.8复制和移动类对象[class.copy]第31段 copy elision 发生时,确切地说:

  

当满足某些条件时,允许实现省略类对象的复制/移动构造[...]。这种复制/移动的省略   在以下情况下允许称为复制省略的操作[...]:

     
      
  • 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-nonqualified类型的非易失性自动对象的名称时,复制/通过构造可以省略移动操作   自动对象直接进入函数的返回值
  •   
  • [...]
  •   

现在我想知道,如果这允许以下代码逃避复制

vector<string> gen(const char *fn) {
    if(fn == nullptr)  // this should prevent RVO
        return {"House", "Horse", "Hen"};
    vector<string> res;
    fillFromFile(res, fn);
    return res;  // copy elision possible?
}
int main() {
    vector<string> data = gen("users.dat");
}

或者那个规则不是这个例子,我必须明确地做这个吗?

    return move(res);  // explicitly prevent copy

请注意,我对if的意图是消除明显的返回值优化(RVO)。

或者我完全走错了轨道?有一个涉及return移动的更改可以使用右值引用,对吗?

2 个答案:

答案 0 :(得分:3)

是的,在这两种情况下都可以/允许复制省略。

在编译器术语中,这两种情况略有不同。 return {"House", "Horse", "Hen"};构造一个未命名的对象,因此常规的RVO会启动。

return res;稍微复杂一点,因为你正在返回一个早先已经构建过的命名对象。此优化通常称为NRVO(命名返回值优化),编译器实现它的情况略为常见。

MSVC始终实施RVO,并在发布版本中执行NRVO。

我相信GCC的最新版本总是同时执行RVO和NRVO。

顺便说一句,我真的不明白为什么你的'if`会对RVO产生影响。

答案 1 :(得分:0)

是的,编译器具有在此上下文中将res视为右值的具体说明,res将移至data。当然,编译器无论如何都可以轻松地在这里应用RVO / NRVO,因为它可以静态地确定你永远不会用nullptr调用函数,此外,函数可以被简单地转换,以便RVO / NRVO甚至可以应用如果无法证明这一点,最后,甚至不能阻止RVO / NRVO,因为仍然可以构建结果。