17

C++11 のムーブ セマンティクスに関する説明をいくつか読んだことがありますが、どのようなコンテキストで使用できるのだろうかと思います。現在、多くの C++ 数学ライブラリは、テンプレート メタプログラミングを使用して評価を遅らせています。

M = A + B + C*D (M、A、B、C、D は行列) の場合、テンプレートのメタプログラミングにより、無駄なコピーを回避できます。移動セマンティクスは、これらの種類のことを行うためのより便利な方法ですか?

そうでない場合、どのコンテキストでムーブ セマンティクスが使用されるか。はいの場合、そのような用途でのテンプレート メタプログラミングとの違い/制限は何ですか?

4

5 に答える 5

34

あなたが「テンプレートメタプログラミング」と呼んでいるもののより正確な用語は、式テンプレートです。

マトリックスがデータを動的に割り当てる場合、移動セマンティクスは、次のような式で生成されたオブジェクトからオブジェクトへのデータの転送 (一時変数との間を含む) に役立ちます。

M = A + B + C*D

一方、式テンプレートは、一時変数を完全に排除します。

行列がデータを動的に割り当てない場合 (たとえば、行列が固定サイズで小さい場合)、移動セマンティクスはパフォーマンスにまったく役立ちません。

式テンプレートをマトリックス ライブラリに適用すると、最高のパフォーマンスが得られます。これも非常に難しい実装手法です。移動セマンティクスは実装がはるかに簡単で、式テンプレートに加えて実行できます (転送できるメモリなどのリソースがある場合)。

要約すれば:

移動セマンティクスは一時メモリを排除しませんが、動的に割り当てられたメモリを一時メモリに再割り当てする代わりに転送します。

式テンプレートは一時的なものを排除します。

于 2012-05-23T18:12:19.263 に答える
13

私はこれらの最適化の専門家では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最終的には次のようになります。CD

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)からコピーする必要がないので、あなたが書いた場合はもっと利用できるものがありますが、それでも結果は遅延評価コードほど良いとは思いません。CA

基本的に、移動セマンティクスは、遅延評価によって提供される最適化のいくつかの重要な部分には役立ちません。

1)評価が遅れているため、中間結果が完全な行列として実際に存在する必要はありません。A+B移動セマンティクスは、ある時点でコンパイラーがメモリー内に完全なマトリックスを作成することを防ぎません。

2)評価が遅れているため、M式全体の計算が完了する前に変更を開始できます。移動セマンティクスは、コンパイラーが変更を並べ替えるのに役立ちません。コンパイラーが潜在的な機会を見つけるのに十分賢い場合でも、例外がスローされる危険がある場合は、非一時的な変更を正しい順序で保持する必要A + B + C * Dがあります。スローの一部であり、M開始時に残しておく必要があります。

于 2012-05-23T18:19:45.217 に答える
2

彼らは2つの異なる獣です。移動セマンティクスとは、破棄される値からリソースを割り当てることです。big int などの式テンプレート (動的なメモリ割り当てが必要) と混合すると、破壊されようとしているもののコピーを作成する代わりに、そのようなメモリを単純に割り当てることができます。

移動セマンティクスは、(fstream のように) 本質的にコピー可能ではないオブジェクトでも重要ですが、moveableにすることは理にかなっています。

于 2012-05-23T18:02:08.533 に答える
0

Move セマンティクスは動的ですが、式テンプレートはそうではありません。複数のステートメントにまたがる式をテンプレート化することはできず、その一部は月が青色の場合にのみ評価されますが、move セマンティクスは可能です。

于 2012-05-23T19:01:07.060 に答える
0

移動セマンティクスは、オブジェクト内で管理されるリソースに適用され、一時オブジェクトが作成されるときに不必要にリソースを取得/解放することを避けるために使用されます (つまり、動的に割り当てられたメモリはリソースです)。

テンプレートのメタプログラミングは、スタックに割り当てられた構造体で動作します (コンパイル時にオペランドの評価が必要なため)。これを使用して、コンパイル時に計算できる操作の実行時の計算を回避できます

于 2012-05-23T18:02:29.553 に答える