[[C++]]

RValueとムーブセマンティクス C++0xの一つのテーマ
http://cpplover.blogspot.jp/2009/11/rvalue-reference_23.html
http://yohhoy.hatenablog.jp/entry/2012/12/15/120839


http://yohhoy.hatenablog.jp/entry/2012/12/15/120839
weak_ptrはshared_ptrが共有するリソースの所有権を持たないため、weak_ptrの監視中に監視対象のリソースを破棄されてしまう 可能性があるのだ。この様な性質を 弱い参照 と呼ぶ。
変数pからqへの所有権の移動は、ポインタのコピー+移動元のNULLクリアの組合せでもちゃんと実現できます。つまり「ムーブセマンティクス」という考え方そのものは、以前からある考え方であり、かつ実装パターン(イディオム)に過ぎない. "p = NULL;"を忘れると... 意図せず pからqへのコピー になり,セマンティクスが破られる.つまりムーブに対するわかりやすい書き方=シンタックスがない.
「ムーブセマンティクス」は以前からある、単なる実装パターン(イディオム)です。
C++11ではコンパイラから「ムーブセマンティクス」を認識できるよう機能拡張します。
この目的のために追加された新機能が「右辺値参照」というシンタックスです。
auto_ptrだけ,代入シンタックスがコピーシンタックスではなくムーブシンタックスを表してしまっている.代入シンタックス u = tは値のコピーというセマンティクスを持つべきですし、C++プログラマにもこれが共通認識としてあるはずです。結局のところ、std::auto_ptrクラスが非推奨となった原因は、シンタックスから期待されるセマンティクスとの不一致、それによる使いづらさ・間違いやすさから来ています。
 = std::move(p1);  // ムーブ代入シンタックス
 p_moved(std::move(p1));  // ムーブコンストラクタシンタックス
return std::move(p) // ムーブリターンシンタックス

複製(コピー)というセマンティクスに利用するのは、「コピーコンストラクタ(copy constructor)」と「コピー代入演算子(copy assignment operator)」シンタックスの2種類です。(ここまでは代入演算子のみ取り上げていました)
T t1, t2, u2;  // Tという適当な型を仮定
T u1( t1 );  // コピーコンストラクタによる"コピー"
u2 = t2;     // コピー代入演算子による"コピー"
最後に、コピー/ムーブに対応するシンタックスを下表にまとめます。ね、簡単でしょ?


コピー
ムーブ
コンストラクタ
T u( t )
T u( std::move(t) )
代入演算子
u = t
u = std::move(t)




T t, u;
std::move(t);      // 何も起こらない...
u = std::move(t);  // tからuへムーブ

C++11で追加されたスレッド間排他制御(ミューテックス)std::mutexのように、コピーもムーブも両方禁止というクラスも存在します。

コピー・ムーブ両方が可能なクラス(ムーブは「最適化されたコピー」, コンテナ系vectorなど, string, move後は“有効だが規定されない状態(valid but unspecified state)”になります。簡単な表現では「中に何がはいっているか知りません(未規定)」だけど「変数への操作は出来るよ(有効)」.要するに未初期化状態と考えれば良い)
コピー禁止だがムーブのみ可能なクラス(ムーブは「所有権の移動」, unique_ptr, move後はからっぽ)
コピー・ムーブ両方が禁止されるクラス(mutex)
コピー・ムーブが両方コピーになるクラス(array, complex)

ムーブセマンティクスを自分で使う.C++03時代だと、この書き方は“コンテナ全体をコピーするなんて非効率極まりない”と四方八方からマサカリが飛んできますが、ムーブセマンティクス対応のC++11以降ではこれがベストになります。ちなみに、上記コードでstd::moveを消してしまえば、C++11であってもC++03時代と同じくコピーが行われます。
「値渡し(pass-by-value)」スタイルを使うのが正解となります。関数twice_vectorの (1)引数の型 と (2)戻り値の型 が、それぞれ普通のIntVecであることに注意して下さい。また (1)関数の呼び出し側 と (2)関数からのreturn文 の両方で std::move を使っていることにも着目してください。

// 全要素値を2倍して返す関数
typedef std::vector<int> IntVec;
IntVec twice_vector(IntVec a)
{
  for (auto& e : a)
    e *= 2;
  return std::move(a);  // (2)"ムーブ"で戻り値を返す
}

IntVec v = { /*...*/ };
IntVec w = twice_vector( std::move(v) );  // (1)"ムーブ"で引数へ値を渡す


右辺参照型
http://yohhoy.hatenablog.jp/entry/2012/12/15/120839

http://d.hatena.ne.jp/osyo-manga/20101117/1289958984
参照渡しは次のような一時的なオブジェクトを受け取ることは出来ません。eigenで苦しんだみたいなやつですね.

http://txt-txt.hateblo.jp/entry/2014/03/22/185633
面白い上きちんと書かれた右辺値参照の記事


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS