我试图弄清楚RVO和NRVO如何与新的C ++ 11移动运算符一起工作。 我已经用一些例子起草了一个虚拟课程。
编辑:只显示代码中最重要的部分。
完整的源代码可用here。
我有两个函数将类作为引用并返回值或引用:
VOpt& fChangeClassRetRef(VOpt &m) {
m.setX(21);
return m;
}
VOpt fChangeClassRetValue(VOpt &m) {
m.setX(21);
return m;
}
当我调用这些函数时,我输出如下:
VOpt &m14 = fChangeClassRetRef(m13);
m14 = fChangeClassRetRef(m11);
-> Copy Assignment Operator
m14 = fChangeClassRetValue(m11);
-> Copy Constructor
-> C++11 Move Operator
使用左值引用时,不会调用复制构造函数。否则,那些函数(接收引用作为参数)仍然会调用复制构造函数。
此功能编译器是否依赖?我做错了吗?
答案 0 :(得分:3)
m14 = fChangeClassRetRef(m11);
-> Copy Assignment Operator
该函数返回一个引用(左值),它不能执行move-assignment,因为参数不是rvalue。
m14 = fChangeClassRetValue(m11);
-> Copy Constructor
-> C++11 Move Operator
在内部触发复制构造函数以创建返回的值。它必须是复制构造函数而不是移动构造函数,因为参数是引用(左值)。将返回值赋值给m14
使用移动赋值运算符,因为参数是右值。
答案 1 :(得分:1)
你有:
// Change the value of the class, return ref!
VOpt& fChangeClassRetRef(VOpt &m) {
m.setX(21);
return m; //#1
}
以这种方式使用:
// VOpt m11;
VOpt m12 = fChangeClassRetRef(m11); // #2
让我们分析一下:#1
返回一个参数的名称(不是局部变量),因此这里既不适用RVO也不适用NRVO。现在fChangeClassRetRef
会返回m
绑定到的位置的引用,其中#2为m11
。因此,我们使用左值m12
初始化m11
。在这种情况下,编译器不能调用移动构造函数,因为它需要一个rvalue,正如我们刚才看到的那样,你提供了一个左值。调用复制构造函数。
另一种情况类似。
VOpt fChangeClassRetValue(VOpt &m) {
m.setX(21);
return m;
}
以这种方式调用:
// VOpt m13;
VOpt &m14 = fChangeClassRetRef(m13);
如上所述,这里既没有RVV,也没有NRVO,因为你要返回一个参数的名字。
函数按值返回,您将返回左值。 (在某些情况下,允许编译器将返回的左值视为rvalue,但不是在这种情况下。)因此无法调用move构造函数并调用复制构造函数。