C++ で小さな数値解析ライブラリをコーディングしています。移動セマンティクスを含む最新の C++11 機能を使用して実装しようとしています。C++11 の右辺値と移動セマンティクスの混乱 (return ステートメント)の議論とトップの回答は理解していますが、まだ頭を抱えているシナリオが 1 つあります。
T
オーバーロードされた演算子を完全に備えたクラスを持っています。また、コピー コンストラクターとムーブ コンストラクターの両方があります。
T (const T &) { /*initialization via copy*/; }
T (T &&) { /*initialization via move*/; }
私のクライアント コードでは演算子を多用しているため、複雑な算術式がムーブ セマンティクスから最大限のメリットを得られるようにしています。次の点を考慮してください。
T a, b, c, d, e;
T f = a + b * c - d / e;
移動セマンティクスがない場合、私のオペレーターは毎回コピー コンストラクターを使用して新しいローカル変数を作成しているため、合計 4 つのコピーがあります。私は、移動セマンティクスを使用して、これを 2 つのコピーといくつかの移動に削減できることを望んでいました。括弧内のバージョン:
T f = a + (b * c) - (d / e);
それぞれがコピーを使用して通常の方法で一時的なものを作成する必要が(b * c)
あり(d / e)
ますが、これらの一時的なものの 1 つを活用して、移動のみで残りの結果を蓄積できれば素晴らしいと思います。
g++ コンパイラを使用してこれを行うことができましたが、私の手法は安全ではないのではないかと考えており、その理由を完全に理解したいと考えています。
加算演算子の実装例を次に示します。
T operator+ (T const& x) const
{
T result(*this);
// logic to perform addition here using result as the target
return std::move(result);
}
T operator+ (T&& x) const
{
// logic to perform addition here using x as the target
return std::move(x);
}
への呼び出しがなければ、各オペレーターstd::move
のバージョンのみが呼び出されます。const &
ただし、std::move
上記のように使用すると、後続の演算 (最も内側の式の後) は&&
各演算子のバージョンを使用して実行されます。
RVO が抑制される可能性があることは知っていますが、非常に計算コストの高い現実世界の問題では、ゲインが RVO の欠如をわずかに上回っているようです。つまり、何百万回もの計算で、 を含めると非常にわずかな速度向上が得られますstd::move
。正直なところ、それがなくても十分に高速です。ここでセマンティクスを完全に理解したいだけです。
私の std::move の使用がここで悪いことであるかどうか、またその理由を簡単な方法で説明するために時間を割いてくれる親切な C++ の第一人者はいますか? よろしくお願いします。