では、r-value 参照では解決できなかったいくつかの問題は何ですか (私が既に知っている完全な転送を除く)?
はい。swap
トリックが機能する (または少なくとも最適に機能する) ためには、構築時にクラスが空の状態になるように設計する必要があります。vector
完全に空から始めるのではなく、常にいくつかの要素を予約する実装を想像してみてください。そのようなデフォルトで構築さvector
れたものから既存のvector
ものと交換することは、(このvector
実装のデフォルト コンストラクターで) 追加の割り当てを行うことを意味します。
実際の移動では、デフォルトで構築されたオブジェクトにデータが割り当てられている可能性がありますが、移動元のオブジェクトは割り当てられていない状態のままになる可能性があります。
また、次のコードを検討してください。
std::unique_ptr<T> make_unique(...) {return std::unique_ptr<T>(new T(...));}
std::unique_ptr<T> unique = make_unique();
これは、言語レベルの移動セマンティクスがなければ不可能です。なんで?2番目のステートメントのため。標準では、これはコピーの初期化です。その名前が示すように、型がcopyableである必要があります。そして、全体的なポイントunique_ptr
は、それが、まあ、ユニークだということです. IE: コピー不可。
移動セマンティクスが存在しない場合は、それを返すことができませんでした。そうそう、コピー省略などについて話すことはできますが、覚えておいてください: 省略は最適化です。準拠するコンパイラは、コピー コンストラクターが存在し、呼び出し可能であることを引き続き検出する必要があります。コンパイラには、それを呼び出さないオプションがあります。
いいえ、移動セマンティクスを でエミュレートすることはできませんswap
。率直に言って、できたとしても、なぜそうしたいのですか?
swap
実装は自分で書く必要があります。したがって、6 つのメンバーを持つクラスがある場合、swap
関数は各メンバーを順番に交換する必要があります。すべての基本クラスなども再帰的に。
C++11 (ただし、VC10 または VC2012 ではありません) では、コンパイラが移動コンストラクターを作成できます。
はい、それなしで逃げることができる状況があります。しかし、それらは信じられないほどハックに見え、なぜそのようにしているのかを理解するのが難しく、何よりも重要なのは、読み手と書き手の両方にとって物事を困難にしています。
swap
パフォーマンスのために、コードを読むのが面倒で、書くのが難しく、エラーが発生しやすくなるようなことをしたい場合 (たとえば、別のメンバーを関数に追加せずにクラスに追加するなど)、次のようにします。おそらく言語の一部になるはずのものを見ています。特に、コンパイラが非常に簡単に処理できるものである場合.