moveしたりforwardしたりするC++0x

今日は野良仕事をしに行っていたわけだが、まぁこのことは後に書くとしよう。

正味の仕事は3時間ほどだったので大したことはなかったが、これでもかなりの効果はあったようで。

手伝いに行った意味もあったものだ。


C++0xやるかと思って、改めてVisual Studio 2010のBeta版を入れてみた。今のところ一番いけてるコンパイラだと思う。(参考記事 : C++0xの化け物じみた右辺値参照)

これを見ると結構いろいろな機能に対応しているね。なかなかよい。

その上でいろいろ試していたのだが、おもしろいこともあるもんだ。


std::unique_ptrという右辺値参照を活用したスマートポインタがあるのだが、これってコンテナに入れられたかなと思って実験してみた。

std::vector<std::unique_ptr<std::string>> v(1);
std::unique_ptr<std::string> p1(new std::string("hage"));
v.at(0)=std::move(p1);
v.push_back(std::unique_ptr<std::string>(new std::string("hoge")));

なんか平然と入れられるし。

std::move付け忘れるとどうなるかって話ですが、へんなエラーが出てコンパイルに失敗する。

まぁしかしこれがいけるならshared_ptrよりもシンプルでいいよね。unique_ptr万歳!

これを回すときですが、せっかくなのでfor_eachしてみた。

std::for_each(v.begin(),v.end(),[](std::unique_ptr<std::string>& p){
  std::cout << *p << std::endl;
});

shared_ptrと違ってコピーできないので参照渡ししないとならん。constは必要に応じてどうぞ。

果たしてこう言うのが便利なのかと言われると難しいが、他のところにコピーして渡す気さえなければいいんじゃないの。


さて、もう左辺値を破壊してしまってもかまわないときにはstd::moveを使うのですが、std::forwardというのもある。

これはテンプレートに関係がある。

template <typename T>
Test TestCreator(T&& other){
  return Test(other);
}

こんなテンプレート関数があったとき、Tの型名は自動で推論される。

もしTest型の右辺値を渡せばT=Testとなるのは容易に予想できる。

ところがTest型の左辺値を渡すとT=Test&となってこのテンプレートが使われる。

なんでやねんという話だがT& &やT& &&やT&& &はT&になるというルールがあるらしく、Test& &&はTest&と同じ意味になってしまうから。

まぁなんにせよ、こう書いておけば右辺値も左辺値も歓迎と言うことになる。

ここで元が右辺値ならstd::moveしたいが、元が右辺値であるかチェックしたいと。

そこでstd::forwardで、これを使うことで判別して適当にしてくれると。

  return Test(std::forward<T>(other));

こんな風に書けば、自動で判定して適当な処理をしてくれる。

右辺値か左辺値かまで完全に転送するからPerfect Forwardingなんだと。

rvalue reference 完全解説 (本の虫)

これを見て初めて理解できた。


それにしてもこの機能はすばらしいね。C++0xすばらしい。

しかしそんな風に言ってますが、C++0xは2000年代にリリースできなかったんですよね。

本来ならC++09みたいになるはずだったのに失敗してしまったと。

果たしてどういう方向にまとまるのか。できるだけ早くまとめてほしいところ。

以下に素晴らしくてもコンパイラが対応してないと使えないもん。