演算から見るC++0x rvalue referenceのパフォーマンスチェック(後編)

前編からの続き

コード

今回は4x4の行列クラスを乗算した時のそれぞれのパフォーマンスを検証します。


行列クラスのヘッダファイル
Matrix.h

#ifndef MATRIX_H__
#define MATRIX_H__

// C++0xで導入された rvalue reference を用いる場合はON
#define RVALUE_REFERENCE

class Matrix44
{
public:
	Matrix44();
	Matrix44(
	    float nm00, float nm01, float nm02, float nm03,
	    float nm10, float nm11, float nm12, float nm13,
	    float nm20, float nm21, float nm22, float nm23,
	    float nm30, float nm31, float nm32, float nm33
	);
	Matrix44(const Matrix44 &t);
	~Matrix44();

	Matrix44 &operator=(const Matrix44 &rhs);
	Matrix44 operator*(const Matrix44 &rhs) const;
	void Set(
	    float nm00, float nm01, float nm02, float nm03,
	    float nm10, float nm11, float nm12, float nm13,
	    float nm20, float nm21, float nm22, float nm23,
	    float nm30, float nm31, float nm32, float nm33
	);

#ifdef RVALUE_REFERENCE
	Matrix44(Matrix44 && t);
	Matrix44 &operator=(Matrix44 && rhs);
	// a  *  (b * c) の様に、右辺が一時オブジェクトの時に使う
	// ※今回のサンプルでは使っていない、資料用
	Matrix44 && operator*(Matrix44 && rhs) const;
	// (a * b)  *  c の様に、左辺が一時オブジェクトの時に使う
	friend Matrix44 && operator*(Matrix44 && lhs, const Matrix44 &rhs);
	// (a * b)  *  (c * d) の様に、両辺一時オブジェクトの時に使う
	// ※今回のサンプルでは使っていない、資料用
	friend Matrix44 && operator*(Matrix44 && lhs, Matrix44 && rhs);
#endif

	// コンストラクタが呼ばれた回数をカウントする
	static long constructorCount;

	friend void Matrix44Mul(Matrix44 &out, const Matrix44 &m1, const Matrix44 &m2);

private:
	union U
	{
		struct
		{
			float m00, m01, m02, m03;
			float m10, m11, m12, m13;
			float m20, m21, m22, m23;
			float m30, m31, m32, m33;
		};
		float m[16];
	};

	// ※std::swapで渡せるようにしておく
	U u;
};

#endif // MATRIX_H__



行列クラスのソースファイル
Matrix.cpp

#include "Matrix.h"

#include <iostream>

long Matrix44::constructorCount = 0;

// 処理を無効化するかどうか
// ※一時オブジェクトや関数のオーバーヘッド計測をする時に有効化します
//#define PROC_DISABLE

Matrix44::Matrix44()
{
#ifndef PROC_DISABLE
	constructorCount++;
	u.m00 = 1.f; u.m01 = 0.f; u.m02 = 0.f; u.m03 = 0.f;
	u.m10 = 0.f; u.m11 = 1.f; u.m12 = 0.f; u.m13 = 0.f;
	u.m20 = 0.f; u.m21 = 0.f; u.m22 = 1.f; u.m23 = 0.f;
	u.m30 = 0.f; u.m31 = 0.f; u.m32 = 0.f; u.m33 = 1.f;
#endif
	//std::cout << "Matrix44()" << std::endl;
}

Matrix44::Matrix44(
    float nm00, float nm01, float nm02, float nm03,
    float nm10, float nm11, float nm12, float nm13,
    float nm20, float nm21, float nm22, float nm23,
    float nm30, float nm31, float nm32, float nm33
)
{
#ifndef PROC_DISABLE
	constructorCount++;
	u.m00 = nm00; u.m01 = nm01; u.m02 = nm02; u.m03 = nm03;
	u.m10 = nm10; u.m11 = nm11; u.m12 = nm12; u.m13 = nm13;
	u.m20 = nm20; u.m21 = nm21; u.m22 = nm22; u.m23 = nm23;
	u.m30 = nm30; u.m31 = nm31; u.m32 = nm32; u.m33 = nm33;
#endif
	//std::cout << "Matrix44(float nm00-nm33)" << std::endl;
}

Matrix44::Matrix44(const Matrix44 &t)
{
#ifndef PROC_DISABLE
	constructorCount++;
	u.m[0] = t.u.m[0]; u.m[1] = t.u.m[1]; u.m[2] = t.u.m[2]; u.m[3] = t.u.m[3];
	u.m[4] = t.u.m[4]; u.m[5] = t.u.m[5]; u.m[6] = t.u.m[6]; u.m[7] = t.u.m[7];
	u.m[8] = t.u.m[8]; u.m[9] = t.u.m[9]; u.m[10] = t.u.m[10]; u.m[11] = t.u.m[11];
	u.m[12] = t.u.m[12]; u.m[13] = t.u.m[13]; u.m[14] = t.u.m[14]; u.m[15] = t.u.m[15];
#endif
	//std::cout << "Matrix44(const Matrix44 &t)" << std::endl;
}

Matrix44::~Matrix44() { }

Matrix44 &Matrix44::operator=(const Matrix44 &rhs)
{
#ifndef PROC_DISABLE
	u.m[0] = rhs.u.m[0]; u.m[1] = rhs.u.m[1]; u.m[2] = rhs.u.m[2]; u.m[3] = rhs.u.m[3];
	u.m[4] = rhs.u.m[4]; u.m[5] = rhs.u.m[5]; u.m[6] = rhs.u.m[6]; u.m[7] = rhs.u.m[7];
	u.m[8] = rhs.u.m[8]; u.m[9] = rhs.u.m[9]; u.m[10] = rhs.u.m[10]; u.m[11] = rhs.u.m[11];
	u.m[12] = rhs.u.m[12]; u.m[13] = rhs.u.m[13]; u.m[14] = rhs.u.m[14]; u.m[15] = rhs.u.m[15];
#endif
	//std::cout << "operator=(const Matrix44 &rhs)" << std::endl;
	return *this;
}

Matrix44 Matrix44::operator*(const Matrix44 &rhs) const
{
	//std::cout << "operator*(const Matrix44 &rhs)" << std::endl;
#ifdef PROC_DISABLE
	return Matrix44();
#else
	return Matrix44(
	           u.m00 * rhs.u.m00 + u.m01 * rhs.u.m10 + u.m02 * rhs.u.m20 + u.m03 * rhs.u.m30,
	           u.m00 * rhs.u.m01 + u.m01 * rhs.u.m11 + u.m02 * rhs.u.m21 + u.m03 * rhs.u.m31,
	           u.m00 * rhs.u.m02 + u.m01 * rhs.u.m12 + u.m02 * rhs.u.m22 + u.m03 * rhs.u.m32,
	           u.m00 * rhs.u.m03 + u.m01 * rhs.u.m13 + u.m02 * rhs.u.m23 + u.m03 * rhs.u.m33,

	           u.m10 * rhs.u.m00 + u.m11 * rhs.u.m10 + u.m12 * rhs.u.m20 + u.m13 * rhs.u.m30,
	           u.m10 * rhs.u.m01 + u.m11 * rhs.u.m11 + u.m12 * rhs.u.m21 + u.m13 * rhs.u.m31,
	           u.m10 * rhs.u.m02 + u.m11 * rhs.u.m12 + u.m12 * rhs.u.m22 + u.m13 * rhs.u.m32,
	           u.m10 * rhs.u.m03 + u.m11 * rhs.u.m13 + u.m12 * rhs.u.m23 + u.m13 * rhs.u.m33,

	           u.m20 * rhs.u.m00 + u.m21 * rhs.u.m10 + u.m22 * rhs.u.m20 + u.m23 * rhs.u.m30,
	           u.m20 * rhs.u.m01 + u.m21 * rhs.u.m11 + u.m22 * rhs.u.m21 + u.m23 * rhs.u.m31,
	           u.m20 * rhs.u.m02 + u.m21 * rhs.u.m12 + u.m22 * rhs.u.m22 + u.m23 * rhs.u.m32,
	           u.m20 * rhs.u.m03 + u.m21 * rhs.u.m13 + u.m22 * rhs.u.m23 + u.m23 * rhs.u.m33,

	           u.m30 * rhs.u.m00 + u.m31 * rhs.u.m10 + u.m32 * rhs.u.m20 + u.m33 * rhs.u.m30,
	           u.m30 * rhs.u.m01 + u.m31 * rhs.u.m11 + u.m32 * rhs.u.m21 + u.m33 * rhs.u.m31,
	           u.m30 * rhs.u.m02 + u.m31 * rhs.u.m12 + u.m32 * rhs.u.m22 + u.m33 * rhs.u.m32,
	           u.m30 * rhs.u.m03 + u.m31 * rhs.u.m13 + u.m32 * rhs.u.m23 + u.m33 * rhs.u.m33
	       );
#endif
}

void Matrix44::Set(
    float nm00, float nm01, float nm02, float nm03,
    float nm10, float nm11, float nm12, float nm13,
    float nm20, float nm21, float nm22, float nm23,
    float nm30, float nm31, float nm32, float nm33
)
{
#ifndef PROC_DISABLE
	u.m00 = nm00; u.m01 = nm01; u.m02 = nm02; u.m03 = nm03;
	u.m10 = nm10; u.m11 = nm11; u.m12 = nm12; u.m13 = nm13;
	u.m20 = nm20; u.m21 = nm21; u.m22 = nm22; u.m23 = nm23;
	u.m30 = nm30; u.m31 = nm31; u.m32 = nm32; u.m33 = nm33;
#endif
}

#ifdef RVALUE_REFERENCE
Matrix44::Matrix44(Matrix44 && t)
{
#ifndef PROC_DISABLE
	constructorCount++;
	//std::swap(u, t.u);
	// 正しくは↑swapだが、 ↓代入の方が若干早い
	u.m[0] = t.u.m[0]; u.m[1] = t.u.m[1]; u.m[2] = t.u.m[2]; u.m[3] = t.u.m[3];
	u.m[4] = t.u.m[4]; u.m[5] = t.u.m[5]; u.m[6] = t.u.m[6]; u.m[7] = t.u.m[7];
	u.m[8] = t.u.m[8]; u.m[9] = t.u.m[9]; u.m[10] = t.u.m[10]; u.m[11] = t.u.m[11];
	u.m[12] = t.u.m[12]; u.m[13] = t.u.m[13]; u.m[14] = t.u.m[14]; u.m[15] = t.u.m[15];
#endif
	//std::cout << "Matrix44(Matrix44 && t)" << std::endl;
}

Matrix44 &Matrix44::operator=(Matrix44 && rhs)
{
#ifndef PROC_DISABLE
	//std::swap(u, rhs.u);
	// 正しくは↑swapだが、 ↓代入の方が若干早い
	u.m[0] = rhs.u.m[0]; u.m[1] = rhs.u.m[1]; u.m[2] = rhs.u.m[2]; u.m[3] = rhs.u.m[3];
	u.m[4] = rhs.u.m[4]; u.m[5] = rhs.u.m[5]; u.m[6] = rhs.u.m[6]; u.m[7] = rhs.u.m[7];
	u.m[8] = rhs.u.m[8]; u.m[9] = rhs.u.m[9]; u.m[10] = rhs.u.m[10]; u.m[11] = rhs.u.m[11];
	u.m[12] = rhs.u.m[12]; u.m[13] = rhs.u.m[13]; u.m[14] = rhs.u.m[14]; u.m[15] = rhs.u.m[15];
#endif
	//std::cout << "operator=(Matrix44 && rhs)" << std::endl;
	return *this;
}

Matrix44 && Matrix44::operator*(Matrix44 && rhs) const
{
#ifndef PROC_DISABLE
	rhs.Set(
	           u.m00 * rhs.u.m00 + u.m01 * rhs.u.m10 + u.m02 * rhs.u.m20 + u.m03 * rhs.u.m30,
	           u.m00 * rhs.u.m01 + u.m01 * rhs.u.m11 + u.m02 * rhs.u.m21 + u.m03 * rhs.u.m31,
	           u.m00 * rhs.u.m02 + u.m01 * rhs.u.m12 + u.m02 * rhs.u.m22 + u.m03 * rhs.u.m32,
	           u.m00 * rhs.u.m03 + u.m01 * rhs.u.m13 + u.m02 * rhs.u.m23 + u.m03 * rhs.u.m33,

	           u.m10 * rhs.u.m00 + u.m11 * rhs.u.m10 + u.m12 * rhs.u.m20 + u.m13 * rhs.u.m30,
	           u.m10 * rhs.u.m01 + u.m11 * rhs.u.m11 + u.m12 * rhs.u.m21 + u.m13 * rhs.u.m31,
	           u.m10 * rhs.u.m02 + u.m11 * rhs.u.m12 + u.m12 * rhs.u.m22 + u.m13 * rhs.u.m32,
	           u.m10 * rhs.u.m03 + u.m11 * rhs.u.m13 + u.m12 * rhs.u.m23 + u.m13 * rhs.u.m33,

	           u.m20 * rhs.u.m00 + u.m21 * rhs.u.m10 + u.m22 * rhs.u.m20 + u.m23 * rhs.u.m30,
	           u.m20 * rhs.u.m01 + u.m21 * rhs.u.m11 + u.m22 * rhs.u.m21 + u.m23 * rhs.u.m31,
	           u.m20 * rhs.u.m02 + u.m21 * rhs.u.m12 + u.m22 * rhs.u.m22 + u.m23 * rhs.u.m32,
	           u.m20 * rhs.u.m03 + u.m21 * rhs.u.m13 + u.m22 * rhs.u.m23 + u.m23 * rhs.u.m33,

	           u.m30 * rhs.u.m00 + u.m31 * rhs.u.m10 + u.m32 * rhs.u.m20 + u.m33 * rhs.u.m30,
	           u.m30 * rhs.u.m01 + u.m31 * rhs.u.m11 + u.m32 * rhs.u.m21 + u.m33 * rhs.u.m31,
	           u.m30 * rhs.u.m02 + u.m31 * rhs.u.m12 + u.m32 * rhs.u.m22 + u.m33 * rhs.u.m32,
	           u.m30 * rhs.u.m03 + u.m31 * rhs.u.m13 + u.m32 * rhs.u.m23 + u.m33 * rhs.u.m33
	);
#endif
	//std::cout << "operator*(Matrix44 && rhs)" << std::endl;
	return std::move(rhs);
}

Matrix44 && operator*(Matrix44 && lhs, const Matrix44 &rhs)
{
#ifndef PROC_DISABLE
	lhs.Set(
	           lhs.u.m00 * rhs.u.m00 + lhs.u.m01 * rhs.u.m10 + lhs.u.m02 * rhs.u.m20 + lhs.u.m03 * rhs.u.m30,
	           lhs.u.m00 * rhs.u.m01 + lhs.u.m01 * rhs.u.m11 + lhs.u.m02 * rhs.u.m21 + lhs.u.m03 * rhs.u.m31,
	           lhs.u.m00 * rhs.u.m02 + lhs.u.m01 * rhs.u.m12 + lhs.u.m02 * rhs.u.m22 + lhs.u.m03 * rhs.u.m32,
	           lhs.u.m00 * rhs.u.m03 + lhs.u.m01 * rhs.u.m13 + lhs.u.m02 * rhs.u.m23 + lhs.u.m03 * rhs.u.m33,

	           lhs.u.m10 * rhs.u.m00 + lhs.u.m11 * rhs.u.m10 + lhs.u.m12 * rhs.u.m20 + lhs.u.m13 * rhs.u.m30,
	           lhs.u.m10 * rhs.u.m01 + lhs.u.m11 * rhs.u.m11 + lhs.u.m12 * rhs.u.m21 + lhs.u.m13 * rhs.u.m31,
	           lhs.u.m10 * rhs.u.m02 + lhs.u.m11 * rhs.u.m12 + lhs.u.m12 * rhs.u.m22 + lhs.u.m13 * rhs.u.m32,
	           lhs.u.m10 * rhs.u.m03 + lhs.u.m11 * rhs.u.m13 + lhs.u.m12 * rhs.u.m23 + lhs.u.m13 * rhs.u.m33,

	           lhs.u.m20 * rhs.u.m00 + lhs.u.m21 * rhs.u.m10 + lhs.u.m22 * rhs.u.m20 + lhs.u.m23 * rhs.u.m30,
	           lhs.u.m20 * rhs.u.m01 + lhs.u.m21 * rhs.u.m11 + lhs.u.m22 * rhs.u.m21 + lhs.u.m23 * rhs.u.m31,
	           lhs.u.m20 * rhs.u.m02 + lhs.u.m21 * rhs.u.m12 + lhs.u.m22 * rhs.u.m22 + lhs.u.m23 * rhs.u.m32,
	           lhs.u.m20 * rhs.u.m03 + lhs.u.m21 * rhs.u.m13 + lhs.u.m22 * rhs.u.m23 + lhs.u.m23 * rhs.u.m33,

	           lhs.u.m30 * rhs.u.m00 + lhs.u.m31 * rhs.u.m10 + lhs.u.m32 * rhs.u.m20 + lhs.u.m33 * rhs.u.m30,
	           lhs.u.m30 * rhs.u.m01 + lhs.u.m31 * rhs.u.m11 + lhs.u.m32 * rhs.u.m21 + lhs.u.m33 * rhs.u.m31,
	           lhs.u.m30 * rhs.u.m02 + lhs.u.m31 * rhs.u.m12 + lhs.u.m32 * rhs.u.m22 + lhs.u.m33 * rhs.u.m32,
	           lhs.u.m30 * rhs.u.m03 + lhs.u.m31 * rhs.u.m13 + lhs.u.m32 * rhs.u.m23 + lhs.u.m33 * rhs.u.m33
	);
#endif
//	std::cout << "operator*(Matrix44 && lhs, const Matrix44 &rhs)" << std::endl;
	return std::move(lhs);
}

Matrix44 && operator*(Matrix44 && lhs, Matrix44 && rhs)
{
//	std::cout << "operator*(Matrix44 && lhs, Matrix44 && rhs)" << std::endl;
	// 一つ↑の Matrix &&operator*(Matrix && lhs, const Matrix44 &rhs) を呼ぶ
	return std::move(lhs) * const_cast<const Matrix44 &>(static_cast<Matrix44 &>(rhs));
}

#endif // RVALUE_REFERENCE


void Matrix44Mul(Matrix44 &out, const Matrix44 &m1, const Matrix44 &m2)
{
#ifndef PROC_DISABLE
	float m[16];
	m[0] = m1.u.m[0] * m2.u.m[0] + m1.u.m[1] * m2.u.m[4] + m1.u.m[2] * m2.u.m[8] + m1.u.m[3] * m2.u.m[12];
	m[1] = m1.u.m[0] * m2.u.m[1] + m1.u.m[1] * m2.u.m[5] + m1.u.m[2] * m2.u.m[9] + m1.u.m[3] * m2.u.m[13];
	m[2] = m1.u.m[0] * m2.u.m[2] + m1.u.m[1] * m2.u.m[6] + m1.u.m[2] * m2.u.m[10] + m1.u.m[3] * m2.u.m[14];
	m[3] = m1.u.m[0] * m2.u.m[3] + m1.u.m[1] * m2.u.m[7] + m1.u.m[2] * m2.u.m[11] + m1.u.m[3] * m2.u.m[15];

	m[4] = m1.u.m[4] * m2.u.m[0] + m1.u.m[5] * m2.u.m[4] + m1.u.m[6] * m2.u.m[8] + m1.u.m[7] * m2.u.m[12];
	m[5] = m1.u.m[4] * m2.u.m[1] + m1.u.m[5] * m2.u.m[5] + m1.u.m[6] * m2.u.m[9] + m1.u.m[7] * m2.u.m[13];
	m[6] = m1.u.m[4] * m2.u.m[2] + m1.u.m[5] * m2.u.m[6] + m1.u.m[6] * m2.u.m[10] + m1.u.m[7] * m2.u.m[14];
	m[7] = m1.u.m[4] * m2.u.m[3] + m1.u.m[5] * m2.u.m[7] + m1.u.m[6] * m2.u.m[11] + m1.u.m[7] * m2.u.m[15];

	m[8] = m1.u.m[8] * m2.u.m[0] + m1.u.m[9] * m2.u.m[4] + m1.u.m[10] * m2.u.m[8] + m1.u.m[11] * m2.u.m[12];
	m[9] = m1.u.m[8] * m2.u.m[1] + m1.u.m[9] * m2.u.m[5] + m1.u.m[10] * m2.u.m[9] + m1.u.m[11] * m2.u.m[13];
	m[10] = m1.u.m[8] * m2.u.m[2] + m1.u.m[9] * m2.u.m[6] + m1.u.m[10] * m2.u.m[10] + m1.u.m[11] * m2.u.m[14];
	m[11] = m1.u.m[8] * m2.u.m[3] + m1.u.m[9] * m2.u.m[7] + m1.u.m[10] * m2.u.m[11] + m1.u.m[11] * m2.u.m[15];

	m[12] = m1.u.m[12] * m2.u.m[0] + m1.u.m[13] * m2.u.m[4] + m1.u.m[14] * m2.u.m[8] + m1.u.m[15] * m2.u.m[12];
	m[13] = m1.u.m[12] * m2.u.m[1] + m1.u.m[13] * m2.u.m[5] + m1.u.m[14] * m2.u.m[9] + m1.u.m[15] * m2.u.m[13];
	m[14] = m1.u.m[12] * m2.u.m[2] + m1.u.m[13] * m2.u.m[6] + m1.u.m[14] * m2.u.m[10] + m1.u.m[15] * m2.u.m[14];
	m[15] = m1.u.m[12] * m2.u.m[3] + m1.u.m[13] * m2.u.m[7] + m1.u.m[14] * m2.u.m[11] + m1.u.m[15] * m2.u.m[15];


	out.u.m[0] = m[0]; out.u.m[1] = m[1]; out.u.m[2] = m[2]; out.u.m[3] = m[3];
	out.u.m[4] = m[4]; out.u.m[5] = m[5]; out.u.m[6] = m[6]; out.u.m[7] = m[7];
	out.u.m[8] = m[8]; out.u.m[9] = m[9]; out.u.m[10] = m[10]; out.u.m[11] = m[11];
	out.u.m[12] = m[12]; out.u.m[13] = m[13]; out.u.m[14] = m[14]; out.u.m[15] = m[15];
#endif
}



main関数があるソースファイル
main.cpp

#include <iostream>

#include <boost/progress.hpp>

#include "Matrix.h"


// 乗算用の関数を用いる場合はON
//#define USE_MULTIPLE_METHOD

// ※↑の他に、Matrix.hに rvalue reference を使うかどうかの
//    プリプロセッサが定義されています。

int main()
{
	boost::progress_timer timer;

	Matrix44 t1, t2, t3, t4, t5, t6, t7, t8, t9;
	Matrix44 t;
	for (int i = 0; i < 1000000; i++)
	{
#ifndef USE_MULTIPLE_METHOD
		t = t1 * t2 * t3 * t4 * t5 * t6 * t7 * t8 * t9;
#else
		Matrix44Mul(t, t1, t2);
		Matrix44Mul(t, t, t3);
		Matrix44Mul(t, t, t4);
		Matrix44Mul(t, t, t5);
		Matrix44Mul(t, t, t6);
		Matrix44Mul(t, t, t7);
		Matrix44Mul(t, t, t8);
		Matrix44Mul(t, t, t9);
#endif
	}

	std::cout << "コンストラクタが呼ばれた回数:" << Matrix44::constructorCount << std::endl;

	return 0;
}


計測

※(7/1)gccに-O2を付けて計測したと勘違いしていた為結果が間違ってました、なので再度計測して書き直しています(太字が加筆です)。
下記が、演算子、関数、rvalue referenceを導入した演算子それぞれの実行時間です、コンパイラgcc 4.5.2(MinGW)、Visual C++ 2010(以下VC++2010)の二つで検証、gccは-O2オプションで最適化、VC++2010はReleaseモードとDebugモードそれぞれで計測しています。
gccは-O2オプション有りと無し、VC++2010はReleaseモードとDebugモードそれぞれで計測しています。
ちなみに、gccコンパイルオプションは下記の通りです。

gcc main.cpp Matrix.cpp -std=c++0x -lstdc++ [-O2] -Iboostのincludeパス -Lboostのlibパス



先ずは、プリプロセッサPROC_DISABLEを有効化した状態で一時オブジェクトの生成や関数のオーバーヘッド計測

演算の種類 コンストラクタが呼ばれた回数(オブジェクト生成数) 10回平均(gcc -O2有り) 10回平均(gcc -O2無し) 10回平均(VC++2010 Release) 10回平均(VC++2010 Debug)
演算子 8000010 0.038sec 0.070sec 0.018sec 0.680sec
関数を使う演算 10 0.012sec 0.016sec 0.006sec 0.199sec
rvalue referenceを導入した演算子 1000010 0.022sec 0.050sec 0.010sec 0.469sec

rvalue referenceを導入した演算子よりも関数の方がオーバーヘッドが小さいようですが、VC++2010のReleaseモードでは微々たる差になっています、それではプリプロセッサPROC_DISABLEを無効化し、行列の乗算時間を加えるとどうなるでしょうか。

演算の種類 コンストラクタが呼ばれた回数(オブジェクト生成数) 10回平均(gcc -O2有り) 10回平均(gcc -O2無し) 10回平均(VC++2010 Release) 10回平均(VC++2010 Debug)
演算子 8000010 0.337sec 0.572sec 0.229sec 1.352sec
関数を使う演算 10 0.306sec 0.492sec 0.256sec 0.758sec
rvalue referenceを導入した演算子 1000010 0.304sec 0.562sec 0.248sec 1.315sec

gccではオーバーヘッド計測の時こそ差があったものの、-O2で最適化すると従来通りに関数を使用した方法とrvalue referenceを導入した演算子が同じ速度となっています。
VC++2010のReleaseモードだとなぜか従来の演算子を使った方法が一番速くなるという結果になりました。
詳しくは不明ですが、おそらく定数を用いた最適化の為に余分なコードが省かれているのだと思います、
なので、試しにMatrix.cppとMatrix.hをReleaseモードでビルドしてMatrix.libを生成し、main.cppをDebugモードでコンパイルして、Matrix.libとリンクするという方法で検証してみると、

演算の種類 コンストラクタが呼ばれた回数(オブジェクト生成数) 10回平均(VC++2010 MatrixをRelease、MainをDebug)
演算子 8000010 0.310sec
関数を使う演算 10 0.282sec
rvalue referenceを導入した演算子 1000010 0.286sec

という結果になりました、おそらくこれが実際に使用した時の速度になるのかと思います。

まとめ

gcc 4.5.2(MinGW)では関数オーバーヘッドの方がまだまだ小さく、従来通りに関数を使用した方法が良いでしょうが、VC++2010ではrvalue referenceを導入すれば演算子を使って分かりやすく書け、実行速度も落ちないのではないかと思います。
gcc 4.5.2(MinGW)、VC++2010共にrvalue referenceを導入すれば演算子を使って分かりやすく書け、実行速度も落ちないのではないかと思います。