【发布时间】:2013-10-16 05:17:34
【问题描述】:
这里有很多关于何时可以完成 RVO 的讨论,但关于何时实际完成的讨论不多。如前所述,RVO 无法根据标准得到保证,但有没有办法保证 RVO 优化成功或相应代码编译失败?
到目前为止,当 RVO 失败时,我部分成功地使代码问题链接错误。为此,我声明了复制构造函数而不定义它们。显然,在我需要实现一个或两个复制构造函数的非罕见情况下,这既不可靠也不可行,即x(x&&) 和x(x const&)。
这就引出了我的第二个问题:为什么编译器编写者选择在用户定义的复制构造函数就位时启用 RVO,而不是在只有默认的复制构造函数存在时?
第三个问题:还有其他方法可以为纯数据结构启用 RVO 吗?
最后一个问题(承诺):你知道任何编译器使我的测试代码表现得与我在 gcc 和 clang 中观察到的不同吗?
这里是 gcc 4.6、gcc 4.8 和 clang 3.3 的一些示例代码,显示了该问题。该行为不依赖于一般优化或调试设置。当然,选项 --no-elide-constructors 会按照它所说的去做,即关闭 RVO。
#include <iostream>
using namespace std;
struct x
{
x () { cout << "original x address" << this << endl; }
};
x make_x ()
{
return x();
}
struct y
{
y () { cout << "original y address" << this << endl; }
// Any of the next two constructors will enable RVO even if only
// declared but not defined. Default constructors will not do!
y(y const & rhs);
y(y && rhs);
};
y make_y ()
{
return y();
}
int main ()
{
auto x1 = make_x();
cout << "copy of x address" << &x1 << endl;
auto y1 = make_y();
cout << "copy of y address" << &y1 << endl;
}
输出:
original x address0x7fff8ef01dff
copy of x address0x7fff8ef01e2e
original y address0x7fff8ef01e2f
copy of y address0x7fff8ef01e2f
RVO 似乎也不适用于普通数据结构:
#include <iostream>
using namespace std;
struct x
{
int a;
};
x make_x ()
{
x tmp;
cout << "original x address" << &tmp << endl;
return tmp;
}
int main ()
{
auto x1 = make_x();
cout << "copy of x address" << &x1 << endl;
}
输出:
original x address0x7fffe7bb2320
copy of x address0x7fffe7bb2350
更新:请注意,一些优化很容易与 RVO 混淆。像make_x 这样的构造函数助手就是一个例子。请参阅this example,其中优化实际上是由标准强制执行的。
【问题讨论】:
-
我认为
make_x不使用 RVO,因为x太小了,只复制它会更有效。如果你让x包含一个更大的数组,它会在我的机器上执行 RVO。 -
既然 C++ 有移动语义,你为什么还要关心执行 RVO?
-
@DanielKO,在那些 RVO/NRVO 比移动对象性能更高的情况下,编译器通常将使用 RVO 而不是移动。
-
@DavidBrown,你说得对。我更新了我的帖子并添加了对我相信您喜欢的另一篇帖子的引用。
标签: c++ c++11 inline compiler-optimization copy-elision