我想知道是否在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
和移动的更改可以使用右值引用,对吗?
答案 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,因为仍然可以构建结果。