忍者ブログ
ゲーム関連の話題に絞っていましたが、全然書かないのでいろいろ解禁してみたり。
[16]  [15]  [14]  [13]  [12]  [11]  [10]  [9]  [8
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

C++0xすごい! Move Semantics最高!ということで個人的なまとめなど。

右辺値参照について詳しく知りたい場合は
http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx
とか
http://d.hatena.ne.jp/ntnek/20090210/p1
とかへどうぞ。

なお、以下のコードは私の理解している物なので間違っているかもです。
VC++2010 Expressで動作確認を行っています。
また、RVOとかNRVOとかは無視しているので最適化によっては別の動作をする事があります。


こんなクラスを作ってみます。

using std::string;

class C
{
public:
 explicit C(const string& s) : s(s){}

 //copy
 C(const C& c) : s(c.s){}

 //copy
 C& operator=(const C& c){
  //copy and swap
  C temp(c);

  std::swap(*this, temp);

  return *this;
 }

 //move
 C(C&& c) : s(std::move(c.s)){}

 //move
 C& operator=(C&& c){
  s = std::move(c.s);

  return *this;
 }

//今やthrowしないswapは必要ない

private:
 string s;
};

このクラスにたいして、こんな事が出来ちゃいます。

C create(const string& s){
 return C(s);
}

int main(){
 C c1 = create("c1");
}

今までなら例外安全性がどうとか言われる所ですが……
create関数内でCのコンストラクタが呼ばれて、作成されたオブジェクトを返します。
そのときにmoveコンストラクタが呼ばれ、c1が初期化されるので、create関数内でオブジェクトの作成が成功した場合、例外が発生することはありません。
(moveは例外を投げないようにしないといけないため)

また、関数内でインスタンスのコピーが必要な場合、以下のように書くと

void copy_use(C c){
 //処理
}

void use(const C& c){
 //処理
}

void out(C& c){
 //処理
}

int main(){
 C c1("c1");
 C& c1ref = c1;

 copy_use(c1);   //1
 copy_use(c1ref);  //2
 copy_use(create("c2")); //3

 use(c1);    //4
 use(c1ref);    //5
 use(create("c2"));  //6

 out(c1);    //7
 out(c1ref);    //8
 //compile error!
 //out(create("c2")); //9
}

1、2の場合はコピーコンストラクタが呼び出されてコピーが作成されますが、3の場合はmoveコンストラクタが呼ばれて余分なコピーは作成されません。
また、今まで通り引数をただ参照したいだけなら4、5、6が、引数の書き換えも行いたい場合は7、8が使用できます。
残念ながらVC++だと9が「非標準の拡張」としてコンパイルが通っちゃうのですけど。警告レベル4にしないと教えてくれないあたり意地悪です。

ちなみに、throwしないswapが必要ないのは、std::swapがmoveを使用してくれるので、そもそも例外がでない上に効率が良いからです。

moveコンストラクタとmove代入演算子は、なるべく上記に習って作成した方がいいです。
なぜなら、規格でこの二つの関数が自動生成されるみたいだからです。
http://d.hatena.ne.jp/faith_and_brave/20100331/1270020213
VC++2010ではまだ実装されていないようですが、将来的に自動生成された物に置き換えられるように……ということです。
後、生ポインタを持っていると、自動生成されるmoveコンストラクタとかmove代入演算子が危ないので、
メンバには生ポインタではなくstd::unique_ptrやstd::shared_ptrに入れた方が良さそうです。標準ですし。
※特にこのあたり、誤解がありそうです。ポインタを持っているクラスなんてたくさんありそうですし、互換性とか大丈夫なのでしょうか……と思うのですけど。まあ、そんなことを行っているプログラムがバグのないまともなプログラムとも思えませんが……

あと、やっぱりVC++2010にはありませんが、こんな物もあるみたいです。
http://d.hatena.ne.jp/faith_and_brave/20081204/1228382167
具体的にどういう事が出来て何がうれしいのかがよくわからないので、とりあえずメモ書きだけ。
 

PR
この記事にコメントする
お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード   Vodafone絵文字 i-mode絵文字 Ezweb絵文字
この記事へのトラックバック
この記事にトラックバックする:
Twitter
Twitter Update
ブログ内検索
カレンダー
05 2025/06 07
S M T W T F S
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
最新コメント
最新トラックバック
プロフィール
HN:
100poisha
性別:
非公開
アクセス解析
Copyright © 100poishaのブログ All Rights Reserved.
Designed by north sound
Powered by Ninja Blog

忍者ブログ [PR]