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

※私個人の検証の結果なので間違っている可能性があります、その時はコメントなりでご連絡ください。
後編はこちら

概要

C++03の時代までは、複数の演算を演算子を用いて書いた時は可読性が良いのですが、一次オブジェクトが何個も作られパフォーマンスが落ちる為、可読性は損なうが演算を関数で行ってなるべく一時オブジェクトが作られるのを防ぐ、というのが一般的でした。C++0xでrvalue referenceが登場した事により、可読性を維持しつつ一時オブジェクト生成によるパフォーマンスの低下を防ぐ事が出来るようになりました。

検証

C++03までの演算子、関数、C++0x以降のrvalue referenceを用いた演算子、それぞれの可読性と一時オブジェクトの数を見ていきます。


演算子の場合:可読性良し、パフォーマンス悪し

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、一時オブジェクトA * m3 -> 一時オブジェクトB、...と作られ、resultに代入される
// ※余分な一時オブジェクトは三つ
// ※演算する対象が増えると、さらに余分な一時オブジェクトが増える事でしょう
result = m1 * m2 * m3 * m4;

関数を使う演算の場合: 可読性悪し、パフォーマンス良し

Matrix44 result;
// ※一時オブジェクトは無し
Mul(&result, m1, m2);
Mul(&result, result, m3);
Mul(&result, result, m4);

rvalue referenceを導入した演算子の場合、可読性良し、パフォーマンス良し

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、一時オブジェクトA * m3 -> 一時オブジェクトA、...と使いまわされ、resultに代入される
// ※余分な一時オブジェクトは一つ
result = m1 * m2 * m3 * m4;



ここで、演算方法を少し変更した別の例を見てみます。


演算子の場合

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、m3 * m4 -> 一時オブジェクトB、一次オブジェクトA * 一時オブジェクトB -> 一時オブジェクトC、と作られ、resultに代入される
// ※余分な一時オブジェクトは三つ
result = (m1 * m2)  *  (m3 * m4);

関数を使う演算の場合

Matrix44 result;
Mul(&result, m1, m2);
// ※一時オブジェクトは一つ
Matrix44 temp;
Mul(&temp, m3, m4);
Mul(&result, result, temp);

rvalue referenceを導入した演算子の場合

Matrix44 result;
// m1 * m2 -> 一時オブジェクトA、m3 * m4 -> 一時オブジェクトB、一次オブジェクトA * 一時オブジェクトB -> 一時オブジェクト(A、Bどちらか流用)、と使いまわされ、resultに代入される
// ※余分な一時オブジェクトは二つ
result = (m1 * m2)  *  (m3 * m4)

やはり演算子の方が見易いです、しかしそれぞれのパフォーマンスはどうだろうか、実際のコードで実行速度を測っていきたいかと思います、って事で後編