4

我想知道当复制省略发生时,是否在 C++0x “ 12.8复制和移动类对象 [class.copy] 第 31 段”中:

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

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

现在我想知道,这是否允许在以下代码中逃避复制

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)。

还是我在这里完全走错了路?有一个涉及returnmove的更改可以使用rvalue references,对吗?

4

2 回答 2

3

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

在编译器术语中,这两种情况略有不同。return {"House", "Horse", "Hen"};构造一个未命名的对象,所以常规的 RVO 开始了。

return res;稍微复杂一些,因为您正在返回一个之前已经构建的命名对象。这种优化通常称为 NRVO(命名返回值优化),编译器实现它的情况稍微少一些。

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

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

顺便说一句,我真的不明白为什么你的“如果”会对 RV​​O 产生影响。

于 2011-04-24T13:29:51.780 回答
0

res是的,编译器有特定的指令在这种情况下像右值一样对待,res并将被移到data. 当然,无论如何,编译器都可以在这里轻松应用 RVO/NRVO,因为它可以静态确定您永远不会使用 调用函数nullptr,此外,可以对函数进行简单的转换,以便即使不能应用 RVO/NRVO被证明,最后,这甚至不会阻止 RVO/NRVO,因为结果仍然可以构建。

于 2011-04-24T13:30:43.120 回答