ぶつぶつ会まとめ
Cryolite さん (id:Cryolite) のぶつぶつ会のまとめです。
開始は 14:20 頃からで、途中に休憩をはさんで終了は 16:20 頃。
今日は N1377をざっと通して読んでいった感じ*1。
で、以下はとってたメモをまとめたものです。move semantics、copy semantics を単に move、copy としてる部分もあるけど気にしない方向で。
あと、リンクの付いてない引用 (枠で囲われた部分) がメモで、リンク付いてるのは基本的には N1337 の引用です。
Motivation から What is needed from the language? まで
Colvin-Gibbonsトリックでムーブセマンティクスの一部はエミュレーションできるが、完全ではない。限界がある。
例えば、auto_ptr<void> p = auto_ptr<int> q;の様に、型変換と所有権の移動を同時にやるのは難しい?無理?*2
なので、言語サポートが欲しい。
ローカルオブジェクトを return する場合、move の方が好ましい。
関数の引数が右辺値か左辺値かで move か copy かをオーバーロード出来るといい。
const 左辺値、const なし左辺値、const 右辺値、const なし右辺値を区別したオーバーロードは C++03 では絶望的。
→一時オブジェクトをバインドできるような参照型が欲しい。
C++03 の参照は、左辺値参照という名前に変わる。
暗黙の型変換された (一時) オブジェクトは右辺値なので、無条件で破壊できる。
Binding temporaries to references
ちょっとよく分からなかったのが以下の部分。
A non-const reference is not always intended to be an "out" parameter. Consider:
template <class T> class auto_ptr { public: auto_ptr(auto_ptr& a); ... };N1377 Binding temporaries to references
出力引数以外の目的で非 const の参照を使うことがあると言って上のコードが示されてるんだけど、これは const だと所有権奪えないから非 const にしないといけない、って話なのかな?
一時オブジェクトをバインド出来る参照型:右辺値参照
で、書き方としては A&& みたいに & を 2 つ連続で書く。
More on A&&
void foo(const A& t); // #1 void foo(A&& t); // #2N1377 More on A&&
左辺値:名前が付いてる・・・関数の引数に渡した後も触る可能性があるので、勝手に書き換えられると困る
void foo(const A& t); をなくすと、意識的に変換しない限り左辺値を foo に渡せなくなる。なぜなら、上の理由。
void foo(const A& t); には右辺値をバインド出来るので、void foo(A&& t); を消しても const A&& なら渡せる*3
ただし、N2844 で左辺値が右辺値参照にバインド出来てしまう例が示されている (conceptと絡めた話)。
→N1377時点では考慮されてなかったっぽい
罠:名前の付いた右辺値参照型のオブジェクトは左辺値
struct A {}; void h(const A&); void h(A&&); void g(const A&); void g(A&&); void f(A&& a) { g(a); // calls g(const A&) h(a); // calls h(const A&) }N1377 More on A&&A&& バージョンに渡したい場合はキャストか N1377 Returning AA&& にある move 関数を使う
move_ptr Example
C++03 の auto_ptr のイケテないところ:
operator= は (STL 等で) コピーを期待しているのに、そうならない。
例:vector< auto_ptr<> >とか
move_ptr:ムーブできるけどコピーできないスマートポインタ
左辺値参照のコピーコンストラクタや operator= は private で宣言することでコンパイルエラーとする (右辺値参照かそうでないかで振り分ける)。
これは C++03 ではたぶん無理
Cast to rvalue
名前の付いたオブジェクトを意図的に破壊したい場合がある。
→右辺値参照にキャストする
swap Example
template <class T> void swap(T& a, T& b) { T tmp(static_cast<T&&>(a)); a = static_cast<T&&>(b); b = static_cast<T&&>(tmp); }N1377 swap Example
move できれば swap できてしまうということがここで言いたいこと。
コピーは重たい。
move は定義できないけど swap は定義できるという場合は、特殊化することで対応する。
*1:アキラさん (id:faith_and_brave) が[http://b2xswg.bay.livefilestore.com/y1pZA4QuwxgEoMgQgE_Infi2co-LmCw78OcTHfY3DXUNcmiPHGOILvlcHAh0TzcHCLPiMiPpslejiljixERqARUoQ/N1377%20A%20Proposal%20to%20Add%20Move%20Semantics%20Support%20to%20the%20C%2B%2B%20Language.pdf?download:title=訳したもの]もどうぞ
*2:ここら辺よく理解してない・・・ あとコード片は IRC のチャットで示されたものそのままです。
*3:自信ないです。