0

我试图弄清楚 RVO 和 NRVO 如何与新的 C++11 移动运算符一起工作。我用几个例子起草了一个虚拟课程。

编辑:只显示代码的最重要部分。

完整的源代码可在此处获得。

我有两个函数将类作为引用并返回值或引用:

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

当使用左值引用时,不会调用复制构造函数。否则,那些函数(接收引用作为参数)仍然调用复制构造函数。

此功能编译器是否依赖?难道我做错了什么?

4

2 回答 2

3
m14 = fChangeClassRetRef(m11);
     -> Copy Assignment Operator

该函数返回一个引用(左值),它不能进行移动赋值,因为参数不是右值。

m14 = fChangeClassRetValue(m11);
     -> Copy Constructor
     -> C++11 Move Operator

复制构造函数在内部触发以创建返回值。它必须是复制构造函数而不是移动构造函数,因为参数是引用(左值)。返回值的m14赋值使用移动赋值运算符作为参数是一个右值。

于 2013-12-03T16:28:23.477 回答
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返回对 wherem绑定的引用,在 #2 中是m11. 因此,我们使用m12m11. 在这种情况下,他的编译器不能调用移动构造函数,因为它需要一个右值,而且正如我们刚刚看到的,您提供的是一个左值。复制构造函数被调用。

另一种情况类似。你有

VOpt fChangeClassRetValue(VOpt &m) {
    m.setX(21);
    return m;
}

就是这样称呼的:

// VOpt m13; 
VOpt &m14 = fChangeClassRetRef(m13);

如上所述,这里既没有 RVO,也没有 NRVO,因为您要返回参数的名称。

该函数按值返回,而您返回的是一个左值。(在某些情况下,允许编译器将返回的左值视为右值,但在这种情况下不是。)因此无法调用移动构造函数并调用复制构造函数。

于 2013-12-03T16:27:11.763 回答