いくつかの記事を読むと、通常、右辺値参照と移動セマンティクスは一緒に説明されています。ただし、私が理解しているように、右辺値参照は右辺値への参照にすぎず、移動セマンティクスとは関係ありません。また、移動セマンティクスは、おそらく右辺値参照を使用しなくても実装できます。問題は、なぜ move constructor/operator= 右辺値参照を使用するのかということです。コードを書きやすくするためだけですか?
2 に答える
問題を考えてみましょう。サポートしたい2つの基本的な移動操作があります。移動「構築」と移動「割り当て」です。コンストラクターやムーブ代入演算子を使用して引用符を実装する必要がないため、ここで引用符を使用します。他のものを使うことができます。
「構築」の移動とは、既存のオブジェクトからコンテンツを転送して新しいオブジェクトを作成することを意味します。これにより、古いオブジェクトを削除しても、新しいオブジェクトで現在使用されているリソースの割り当てが解除されません。「割り当て」の移動とは、既存のオブジェクトを取得し、既存のオブジェクトからコンテンツを転送することを意味します。これにより、古いオブジェクトを削除しても、新しいオブジェクトで現在使用されているリソースの割り当てが解除されません。
OK、これが私たちがやりたい操作です。さて、それを行う方法は?
「建設」を動かしてください。コンストラクター呼び出しでこれを実装する必要はありませんが、本当に実装したいと思います。魔法の関数呼び出しの背後にある場合でも、2段階の移動構築を強制したくありません。したがって、コンストラクターとして移動を実装できるようにする必要があります。いいよ。
問題1:コンストラクターには名前がありません。したがって、引数のタイプとオーバーロードの解決に基づいてのみ区別できます。T
また、型のオブジェクトの移動コンストラクターは、型のオブジェクトをパラメーターとして受け取る必要があることもわかっていT
ます。また、必要な引数は1つだけなので、コピーコンストラクターとまったく同じように見えます。
さて、オーバーロードを満たすための何らかの方法が必要です。いくつかの標準ライブラリタイプを導入することができstd::move_ref
ます。のようstd::reference_wrapper
になりますが、別のタイプになります。したがって、moveコンストラクターは。を取るコンストラクターであると言えますstd::move_ref<T>
。了解しました。問題は解決しました。
だけではありません。今、新しい問題があります。このコードを考えてみましょう:
std::string MakeAString() { return std::string("foo"); }
std::string data = MakeAString();
省略を無視すると、C ++ 11の式の値のカテゴリの規則では、関数から値によって返される型はprvalueであると規定されています。したがって、可能な限り、移動コンストラクター/代入演算子によって自動的に使用されます。等の必要はありません。std::move
それをあなたのやり方で行うには、これが必要になります:
std::string MakeAString() { return std::move(std::string("foo")); }
std::string data = std::move(MakeAString());
コピーを回避するには、これらのstd::move
呼び出しの両方が必要になります。一時的なものから戻り値に移動してから、戻り値から移動してdata
(ここでも、省略を無視して)移動する必要があります。
これが単なる小さな煩わしさだと思う場合は、他に価値のある参照が私たちに何を買うかを考えてください。完璧な転送です。特別な参照折りたたみルールがないと、コピーと移動のセマンティクスを完全に転送する適切な転送関数を作成できませんでした。std::move_ref
実際のC++タイプになります。右辺値参照の場合のように、参照が折りたたまれるような任意のルールを単純に叩くことはできません。
結局のところ、単なるライブラリタイプではなく、ある種の言語構造が必要です。これを新しい種類の参照にすることで、その参照にバインドできるもの(およびバインドできないもの)の新しいルールを定義できるようになります。そして、完全な転送を可能にする特別な参照折りたたみルールを定義することができます。
接続は、右辺値から移動しても安全であるということです((キャストがない場合)右辺値は寿命の終わりにあるオブジェクトを参照するため)、右辺値参照を取るコンストラクターは、盗み/参照されたオブジェクトから移動します。
C++ 言語の観点からは、これが接続の終わりですが、標準ライブラリは、左辺値のコピーからの構築と右辺値の移動からの構築を一貫して作成し、作成するヘルパー関数 ( など) を提供することにより、この接続をさらに拡張しますstd::move
。特定のオブジェクトを移動またはコピーするかどうかを選択するのは簡単です (コピー/移動を引き起こす式でオブジェクトの値カテゴリを変更することによって)。
移動セマンティクスは、右辺値参照なしで実装できますが、あまりきれいではありません。多くの問題を解決する必要があります。
const 以外の参照で右辺値をキャプチャする方法は?
コピーするコンストラクタと移動するコンストラクタを区別する方法は?
移動が安全な最適化である場所で確実に使用されるようにするにはどうすればよいですか?
移動可能なオブジェクトとコピー可能なオブジェクトの両方で機能する汎用コードを作成するには?