私はこれらの最適化の専門家ではA+B+C*D
ありませんが、たとえば行列を返さないように行列型に算術演算子を定義することで作業について話している遅延評価手法を理解しているので、次のようなプロキシオブジェクトを返します。マトリックスに変換できます。これは、に割り当てられたときに発生しM
、変換コードは、一時的な行列オブジェクトを避けて、ライブラリ設計者が考え出すことができる最も効率的な方法で結果行列の各セルを計算します。
したがって、プログラムに次のものが含まれているとします。M = A + B + C * D;
operator+
を使用して通常の方法で実装する以外に賢いことを何もしなかった場合、operator+=
通常のC++03スタイルのコピーの省略が開始されたら次のようなものが得られます。
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += tmp1;
M = tmp2;
評価が遅れると、次のような結果になる可能性があります。
for (int i = 0; i < M.rows; ++i) {
for (int j = 0; j < M.cols; ++j) {
/* not necessarily the best matrix multiplication, but serves to illustrate */
c_times_d = 0;
for (int k = 0; k < C.cols; ++k) {
c_times_d += C[i][k] * D[k][j];
}
M[i][j] = A[i][j] + B[i][j] + c_times_d;
}
}
一方、「何も賢くない」コードは、いくつかの個別の加算ループとより多くの割り当てを実行します。
私の知る限り、この場合、移動セマンティクスはあまり役に立ちません。あなたが書いたものには、、、、またはから移動することを許可するものは何もないA
ので、B
最終的には次のようになります。C
D
Matrix tmp1 = C;
tmp1 *= D;
Matrix tmp2 = A;
tmp2 += B;
tmp2 += std::move(tmp1);
M = std::move(tmp2);
したがって、移動セマンティクスは、演算子の右辺値バージョンが通常のバージョンよりも優れている可能性がある最後のビット以外には役立ちませんでした。またはstd::move(A) + std::move(B) + std::move(C) * std::move(D)
からコピーする必要がないので、あなたが書いた場合はもっと利用できるものがありますが、それでも結果は遅延評価コードほど良いとは思いません。C
A
基本的に、移動セマンティクスは、遅延評価によって提供される最適化のいくつかの重要な部分には役立ちません。
1)評価が遅れているため、中間結果が完全な行列として実際に存在する必要はありません。A+B
移動セマンティクスは、ある時点でコンパイラーがメモリー内に完全なマトリックスを作成することを防ぎません。
2)評価が遅れているため、M
式全体の計算が完了する前に変更を開始できます。移動セマンティクスは、コンパイラーが変更を並べ替えるのに役立ちません。コンパイラーが潜在的な機会を見つけるのに十分賢い場合でも、例外がスローされる危険がある場合は、非一時的な変更を正しい順序で保持する必要A + B + C * D
があります。スローの一部であり、M
開始時に残しておく必要があります。