二进制操作员返回XVALUE而不是prvalue

Binary Operators Return Xvalue Instead of PRvalue?

本文关键字:prvalue XVALUE 操作员 返回 二进制      更新时间:2023-10-16

根据此博客 - 我意识到这是旧的,如果不再考虑相关的话,请告诉我 - 实施二进制操作员的最佳方法是以下...

// The "usual implementation"
Matrix operator+(Matrix const& x, Matrix const& y)
{ Matrix temp = x; temp += y; return temp; }
// --- Handle rvalues ---
Matrix operator+(Matrix&& temp, const Matrix& y)
{ temp += y; return std::move(temp); }
Matrix operator+(const Matrix& x, Matrix&& temp)
{ temp += x; return std::move(temp); }
Matrix operator+(Matrix&& temp, Matrix&& y)
{ temp += y; return std::move(temp); }

我测试了此实现,并在以下表达式中进行了...

a + b + c + d

在它们都是矩阵的地方,我最终得到了我不认为是必要的许多移动构造函数和驱动器调用。如果将所有操作员的返回类型更改为矩阵& amp;',您消除了所有移动构造函数,只需要一个单个驱动器调用。

我制作了一个简单的程序,可以在此处使用代码显示两个实现。

有人可以解释这样做是否错误/不好,为什么?我想不出一个原因,为什么不这样做。它节省了许多构造函数和破坏器调用,并且似乎并没有打破任何内容。

您在此处使用移动构造函数对代码进行修饰。矩阵添加可以安全地完成,而根本没有移动构造函数,并且编译器足够聪明以将其优化。

这是一些测试代码,可以证明我在说什么:

#include <stdint.h>
class Matrix3
{
public:
    float Mtx[3][3];
    inline Matrix3() {};
    inline Matrix3 operator+( const Matrix3& Matrix ) const
    {
        Matrix3 Result;
        for ( size_t i = 0; i != 3; ++i )
        {
            for ( size_t j = 0; j != 3; ++j )
            {
                Result.Mtx[i][j] = Mtx[i][j] + Matrix.Mtx[i][j];
            }
        }
        return Result;
    }
    virtual int GetResult() const
    {
        int Result = 0;
        for ( size_t i = 0; i != 3; ++i )
        {
            for ( size_t j = 0; j != 3; ++j )
            {
                Result += (int)Mtx[i][j];
            }
        }       
        return Result;
    }
};
int main()
{
    Matrix3 M;
    Matrix3 M1;
    Matrix3 M2;
    Matrix3 M3;
    Matrix3 M4;
    M = M1 + M2 + M3 + M4;
    return M.GetResult();
}

我使用GCC: (GNU) 4.9.0 20131110 (experimental)如下:g++ -O3 main.cpp -S

输出组件看起来如下:

_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $176, %esp
    call    ___main
    fnstcw  14(%esp)
    fldz
    fadd    %st(0), %st
    fadds   LC0
    fadds   LC0
    fsts    140(%esp)
    movl    140(%esp), %eax
    fsts    144(%esp)
    movl    %eax, 20(%esp)
    movl    144(%esp), %eax
    fsts    148(%esp)
    movl    %eax, 24(%esp)
    fsts    152(%esp)
    movl    148(%esp), %eax
    fsts    156(%esp)
    movl    %eax, 28(%esp)
    fsts    160(%esp)
    movl    152(%esp), %eax
    fsts    164(%esp)
    movl    %eax, 32(%esp)
    fsts    168(%esp)
    movl    156(%esp), %eax
    fstps   172(%esp)
    movl    %eax, 36(%esp)
    movl    160(%esp), %eax
    flds    24(%esp)
    movl    %eax, 40(%esp)
    movl    164(%esp), %eax
    movl    %eax, 44(%esp)
    movl    168(%esp), %eax
    movl    %eax, 48(%esp)
    movl    172(%esp), %eax
    movl    %eax, 52(%esp)
    movzwl  14(%esp), %eax
    movb    $12, %ah
    movw    %ax, 12(%esp)
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %edx
    flds    20(%esp)
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    28(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    32(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    36(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    40(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    44(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    48(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    flds    52(%esp)
    addl    %eax, %edx
    fldcw   12(%esp)
    fistpl  8(%esp)
    fldcw   14(%esp)
    movl    8(%esp), %eax
    leave
    addl    %edx, %eax
    ret

根本没有任何复制/移动构造函数或任何功能调用的单个跟踪。一切都将其展开为快速的数学磨练指令流。

认真地说,无需为R值编写其他处理程序。编译器没有它们制作完美的代码。