ぶつぶつ会まとめ

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);       // #2
N1377 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:自信ないです。