C++0x むーぶせまんちくす
くらいおらいと1自己紹介• 名前： Cryolite• ふりがな： くらいおらいと• 出身地： 大阪市• 興味のあること： C++, STL, Boost, C++0x• ブログなど： “Cryolite” で検索• お仕事：– 日本語の文を単語に分けるお仕事– 機械に学習させるお仕事2ムーヴ

C/C++ においては・・・

オブジェクト操作の基本はコピー
汎用ライブラリの運用実績

ムーヴの出番関数からの戻り値

C++ではムーヴも重要な操作じゃね？
C++03 ではムーブは面倒
C++0x では

動的配列の再配置

一時オブジェクト
etc…

ムーヴのための言語サポート！
3

セッションの流れ• C++03 におけるコピーの重要性とその限界• ムーヴの導入 – 動的配列再配置の例から• ムーヴの活用例– ローカルオブジェクトの return– 一時オブジェクト• ムーヴのための C++0x 言語機能 – 右辺値参照• 明示的なムーヴ• まとめ4セッションの流れ• C++03 におけるコピーの重要性とその限界• ムーヴの導入 – 動的配列再配置の例から• ムーヴの活用例– ローカルオブジェクトの return– 一時オブジェクト• ムーヴのための C++0x 言語機能 – 右辺値参照• 明示的なムーヴ• まとめ5

コピー
int i = 42;
int j = i;class String{.....
private:char *p_;
std::size_t sz_;};
String s(“Hello!”);String t = s;4242p_=0x1234
sz_=6

p_=0x2345
sz_=6“Hellow!”“Hellow!”コピーの出番 – 戻り値の生成
int plus(int lhs, int rhs){
int result = lhs;
result += rhs;
return result;}result（戻り値）

42427

コピーの出番 – 一時オブジェクトからのコピー

int i = plus(18, 24);

result（戻り値）

42428

コピーの出番 – 動的配列の再配置
長さ3， capacity=3 の int の動的配列に int オブジェクトを1つ追加

std::vector<int>
p_=0x2345
sz_=442424242
4242429

コピーの限界• コピーが重いオブジェクト• コピーできないオブジェクト10コピーの弱点その1 – コピーが重いオブジェクトの存在

Stringp_ = 0x1234
sz_ = 13

Hello, world!

Stringp_ = 0x2345
sz_ = 13

Hello, world!

•フリーストア (ヒープ) 上のメモリ領域が必要•可能ならばこの領域の確保を回避したい11コピーの弱点その2 – コピーできないオブジェクトの存在
ファイル

ソケット

コピーできないオブジェクトの存在

ストリーム

スレッド

プロセス
etc…
12

コピーの限界•コピーの重いオブジェクトを扱うと効率が悪いのか？
•重いオブジェクトは以下の点で非効率；•動的配列の再配置•戻り値として指定•一時オブジェクトの生成•コピーできないオブジェクトを扱えないのか？
•コピーできないオブジェクトは以下が直接できない；•動的配列に乗せる•戻り値として指定•一時オブジェクトからコピー

13セッションの流れ• C++03 におけるコピーの重要性とその限界• ムーヴの導入 – 動的配列再配置の例から• ムーヴの活用例– ローカルオブジェクトの return– 一時オブジェクト• ムーヴのための C++0x 言語機能 – 右辺値参照• 明示的なムーヴ• まとめ14

ムーヴの導入 – 動的配列の再配置の例

長さ3, capacity=3 の動的配列 (std::vector) の例

std::vector<String>
p_ = 0x1234
sz_ = 3p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

15ムーヴの導入 – 動的配列の再配置の例
p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

std::vector<String>
p_ = 0x1234
sz_ = 4

新たに挿入

16ムーヴの導入 – 動的配列の再配置の例
もしも，文字列オブジェクトの private メンバを触っても良いとしたら？

std::vector<String>
p_ = 0x1234
sz_ = 4

新たに挿入

p_ = 0, sz_ = 0

Hello, world!

p_ = 0, sz_ = 0

Hello, world!

p_ = 0, sz_ = 0

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

p_ = …, sz_ = 13

Hello, world!

ポインタをつなぎかえるだけで完了

17

コピー vs. 直接操作
Hello, world!

p=…, sz=…

Hello, world!

p=…, sz=…

p=…, sz=13
p=…, sz=13
p=…, sz=4

p=…, sz=13

p=…, sz=…

Hello, world!

Hello, world!

p=…, sz=4
Hello, world!
p=…, sz=13
p=…, sz=13

Hello, world!
Hello, world!

p=…, sz=13

Hello, world!

p=…, sz=13

Hello, world!

p=…, sz=13
p=…, sz=13

Hello, world!

p=…, sz=13

p=…, sz=13
Hello, world!

コピーによる操作→ ○抽象化

コピーによるリソースの再確保 → ×効率

ポインタのつなぎかえのみ → ○効率
private メンバ直接操作→ ×抽象化

右側における文字列オブジェクトの操作を抽象化ムーヴ – 文字列オブジェクトの例
移動元（ソース）

移動先（ターゲット）

p=0x1234, sz=13

p=…, sz=…

Hello, world!

Hello, world!

p=0x0000, sz=0

p=0x1234, sz=13

19

コピーとムーヴの比較
コピー元

コピー先

移動元（ソース）

p=…, sz=…

p=…, sz=…

p=…, sz=…

p=…, sz=…
Hello, world!

Hello, world!

コピー元

コピー先

移動元（ソース）

p=…, sz=…

p=…, sz=…

p=0, sz=0

Hello, world!

Hello, world!

コピー元は不変

移動先（ターゲット）

移動先（ターゲット）
p=…, sz=…
Hello, world!

ムーヴ元は変わるかも知れない20

セッションの流れ• C++03 におけるコピーの重要性とその限界• ムーヴの導入 – 動的配列再配置の例から• ムーヴの活用例– ローカルオブジェクトの return– 一時オブジェクト• ムーヴのための C++0x 言語機能 – 右辺値参照• 明示的なムーヴ• まとめ21

戻り値へのコピー
String operator+(const String& lhs,const String& rhs){
String result(lhs);// lhs に rhs の文字列を連結
return result;}

return 文以降 result は使わない

ムーヴで十分！

（戻り値）

resultp = 0x1234
sz = 13

hogefugap = 0x2345

hogefugasz = 1322戻り値へのムーヴ
String operator+(const String& lhs,const String& rhs){
String result(lhs);// lhs に rhs の文字列を連結
return result;}

return 文以降 result は使わない

ムーヴで十分！

（戻り値）

resultp = 0x0000
sz = 0p = 0x2345
hogefuga

hogefugasz = 1323

一時オブジェクトとコピー
String h(“Hello, ”);
String w(“world!”);String str = h + w;

„h + w‟ で作られる一時オブジェクトは‘str‟ の初期化以外に使われない

ムーヴで十分！

(„h + w‟ で作られた一時オブジェクト)
p = 0x1234
sz = 13

hogefugastrp = 0x2345

hogefugasz = 1324

一時オブジェクトとコピー
String h(“Hello, ”);
String w(“world!”);String str = h + w;

„h + w‟ で作られる一時オブジェクトは‘str‟ の初期化以外に使われない

ムーヴで十分！

(„h + w‟ で作られた一時オブジェクト)
p = 0x1234
sz = 13

hogefugastrhogefugap = 0x2345
sz = 1325

セッションの流れ• C++03 におけるコピーの重要性とその限界• ムーヴの導入 – 動的配列再配置の例から• ムーヴの活用例– ローカルオブジェクトの return– 一時オブジェクト• ムーヴのための C++0x 言語機能 – 右辺値参照• 明示的なムーヴ• まとめ26

ムーヴのための C++0x 言語機能
String h(“Hello, ”);String str = h;String h(“Hello, ”);
String w(“world!”);String str = h + w;

h は名前の付いたオブジェクト（左辺値）„h + w‟ は名前の付いていないオブジェクト (右辺値) を生成

勝手に壊さないでほしい„str‟ のコンストラクタは右辺値を勝手に破壊して O.K.

従来のコピーコンストラクタを起動

ムーヴを用いたコンストラクタを起動

左辺値と右辺値を自動で区別したい
27

ムーヴのための C++0x 言語機能 – 右辺値参照

従来の参照型 &+2つの参照型でそれぞれ関数をオーバーロード可能

新しい参照型 && (右辺値参照型)

class String {.....
String(const String& x);.....
String(String&& x);
.....
};

従来と同じコピーコンストラクタ
右辺値参照型でオーバーロードした
コンストラクタ (ムーヴコンストラクタ)

28

ムーヴコンストラクタの実装 – 文字列クラスの例class String {String(const String& x)
コピーコンストラクタ: p_(), sz_(){ p_ = new char[x.sz_];
sz_ = x.sz_;
std::copy(x.p_, x.p_ + x.sz_, p_); }String(String&& x): p_(x.p_), sz_(x.sz_){ x.p_ = 0;x.sz_ = 0; }.....
private:char *p_; std::size_t sz_;};

ムーヴコンストラクタ

29

ムーヴコンストラクタの実装 – 文字列クラスの例
String h(“Hello, ”);
String str = h;

コピーコンストラクタを起動

String h(“Hello, ”);
String w(“world!”);String str = h + w;

ムーヴコンストラクタを起動

class String {.....
String(const String& x);.....
String(String&& x);
.....
};

30

セッションの流れ• C++03 におけるコピーの重要性とその限界• ムーヴの導入 – 動的配列再配置の例から• ムーヴの活用例– ローカルオブジェクトの return– 一時オブジェクト• ムーヴのための C++0x 言語機能 – 右辺値参照• 明示的なムーヴ• まとめ31

オブジェクトを捨てる
std::vector<String> vec;
String str(“Hello, world!”);vec.push_back(str);// 以降， ‘str‟ は使わない
String my_name(“Cryolite”);
int my_age = 28;
Person me(my_name, my_age);// 以降， ‘my_name‟ は使わない

std::vector オブジェクトやPerson オブジェクトに文字列オブジェクトを載せるためだけの文字列オブジェクトたち

従来は，このような場合でもコピーを使っていた

vec や me に渡すときはムーヴで十分32まとめ• コピーとともに C++ で重要なムーヴについて，具体例とともに紹介– 動的配列の再配置– 戻り値へのムーヴ– 一時オブジェクトからのムーヴ• ムーヴを扱いやすくするための C++0x 言語
仕様 – 右辺値参照 – について紹介

33

このプレゼンで話さなかった大切なこと• ムーヴした後のオブジェクトはどうなるの？
• ムーヴと例外安全• 完全な転送 (perfect forward)• *this とムーヴ

34

右辺値参照に関するオンラインドキュメント• （日本語での右辺値参照の紹介は少ない）• “A Proposal to Add Move Semantics
Support to the C++ Language”– “N1377” で検索 (邦訳有)• http://d.hatena.ne.jp/ntnek/20090210/– “ntnek 右辺値参照” で検索 (邦訳)

• “A Brief Introduction to Rvalue
References” (英語)35