【发布时间】:2012-04-14 16:59:40
【问题描述】:
假设我想实现一个函数,该函数应该处理一个对象并返回一个新的(可能已更改的)对象。我想在 C+11 中尽可能高效地做到这一点。环境如下:
class Object {
/* Implementation of Object */
Object & makeChanges();
};
我想到的替代方案是:
// First alternative:
Object process1(Object arg) { return arg.makeChanges(); }
// Second alternative:
Object process2(Object const & arg) { return Object(arg).makeChanges(); }
Object process2(Object && arg) { return std::move(arg.makeChanges()); }
// Third alternative:
Object process3(Object const & arg) {
Object retObj = arg; retObj.makeChanges(); return retObj;
}
Object process3(Object && arg) { std::move(return arg.makeChanges()); }
注意:我想使用像 process() 这样的包装函数,因为它会做一些其他工作,我希望尽可能多地重用代码。
更新:
我使用带有给定签名的makeChanges(),因为我正在处理的对象提供了具有该类型签名的方法。我猜他们将其用于方法链接。我还修复了提到的两个语法错误。感谢您指出这些。我还添加了第三种选择,我将在下面提出问题。
用 clang 试试这些 [i.e. Object obj2 = process(obj);] 结果如下:
第一个选项对复制构造函数进行两次调用;一个用于传递参数,一个用于返回。可以改为说return std::move(..) 并调用一次复制构造函数和一次调用移动构造函数。我知道 RVO 无法摆脱这些调用之一,因为我们正在处理函数参数。
在第二个选项中,我们仍然有两次调用复制构造函数。在这里,我们进行了一次显式调用,并在返回时进行了一次调用。我期待 RVO 能够加入并摆脱后者,因为我们返回的对象是与参数不同的对象。然而,这并没有发生。
在第三个选项中,我们只有一次对复制构造函数的调用,即显式调用。 (N)RVO 消除了我们为返回而执行的复制构造函数调用。
我的问题如下:
- (已回答)为什么 RVO 使用最后一个选项而不是第二个选项?
- 有没有更好的方法来做到这一点?
- 如果我们传入一个临时的,第二个和第三个选项将在返回时调用一个移动构造函数。是否可以使用 (N)RVO 消除这种情况?
谢谢!
【问题讨论】:
-
为什么
makeChanges会返回Object&?它应该不返回任何内容并且是一个变异函数,或者它应该是const并按值返回一个新对象。目前,因为它是 notconst,所以您列出的第一个和第二个选项甚至无法编译,因为您正在调用 const 对象上的非 const 成员函数。实际上,如果没有makeChanges' 当前签名的理由,这会使您的问题变得非常荒谬。 -
@ildjarn:感谢 cmets。我进行了更改并提出了问题。我想我仍然不清楚 RVO 如何/何时启动。我很想听听您的想法和建议。
标签: c++ c++11 move-semantics return-value-optimization