为什么 g++ 在这里不启用 RVO?
考虑一下测试代码:
#include <iostream>
using namespace std;
class Klass
{
public:
Klass()
{
cout << "Klass()" << endl;
}
Klass(const Klass& right)
{
cout << "Klass(const Klass& right)" << endl;
}
};
Klass create(Klass a)
{
cout << "create(Klass a)" << endl;
return a;
}
int main()
{
const Klass result = create(Klass());
}
编译:
g++ -O3 rvo.cpp -o rvo
输出是:
$ ./rvo
Klass()
create(Klass a)
Klass(const Klass& right)
我希望编译器使用 RVO 机制来省略每个 COPY CTOR 调用,以避免复制返回值和函数 create()
的参数.为什么不是这样?
I was expecting the compiler to use the RVO mechanism in order elide every COPY CTOR call, to avoid copying the return value AND the parameter of the function create()
. Why isn't it the case?
推荐答案
你看到的副本是create"函数中return"语句的副本.它不能被 RVO 消除,因为不可能直接构造返回值.您要求退货".这里需要一份副本;没有它就无法返回对象.
The copy you see is a copy for the "return" statement in the "create" function. It cannot be eliminated by RVO, as it is not possible to construct the return value directly. You requested to "return a". A copy is needed here; there is no way to return an object without it.
通俗地说,[C++11: 12.8/31] 的以下条件不满足
In a standard speak, following condition of [C++11: 12.8/31] is not met
在具有类返回类型的函数的返回语句中,当表达式是非易失性自动对象的名称(不是function 或 catch-clause parameter) 具有与函数返回类型相同的 cv-unqualified 类型,则可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作
in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value
至于原因,这不是一个任意规则,从实现的角度来看是有道理的,因为这是函数参数无法做到的:
As for the reasons, it is not an arbitrary rule, it makes sense from implementation point of view, as this is what is not possible to do with a function parameters:
将自动对象直接构造成函数的返回值
constructing the automatic object directly into the function’s return value
您正在复制函数参数.没有内联就不能省略这个副本,因为参数在输入函数之前已经存在,因此不能直接将该对象构造为返回值.
You are copying the function parameter. You cannot elide this copy without inlining, as the parameter already exists before you enter the function, therefore you cannot construct that object into the return value directly instead.
相关文章