コミケ告知

サークル活動の詳細は circle タグの記事へ。
2013年3月12日火曜日

BOOST_FOREACHは参照で受けないとコピーされる

C++でループを回てコレクションを巡回するときに時折役に立つ、BOOST_FOREACH。(boost/foreach.hpp)
便利なんですが、巡回先のコレクションから受け側の変数に代入されるだけなので、参照で受けないとコピーされます。

以下のような、テスト用にコンストラクタ・デストラクタでprintfするだけの適当なクラスがあるとして。
class Hoge {
  public:
    Hoge() { printf("ctor %p\n", this); }
    Hoge(const Hoge& h) { printf("copy %p\n", this); }
    ~Hoge() { printf("dtor %p\n", this); }
};
気を使わずに単に変数で受けて巡回すると…
vector<hoge> hoge_vector(3);
BOOST_FOREACH(Hoge x, hoge_vector) { ; }
ctor 0x20010210
ctor 0x20010211
ctor 0x20010212
copy 0x28ac26
dtor 0x28ac26
copy 0x28ac26
dtor 0x28ac26
copy 0x28ac26
dtor 0x28ac26
dtor 0x20010210
dtor 0x20010211
dtor 0x20010212
ですよねー。参照(&x)で受けないと、スタック上にコピーして破棄してを繰り返しています。関数の引数でオブジェクトを値渡し、みたいな話でちょっと恥ずかしい。 boost.org公式のドキュメントにも、"Iterate over a sequence by reference, and modify the underlying sequence" という例が書いてあります。

参考:公式ドキュメント

参照で受ければ、もちろんコピーされずに済みます。
BOOST_FOREACH(Hoge &x, hoge_vector) { ; }
ctor 0x20010210
ctor 0x20010210
ctor 0x20010211
ctor 0x20010212
dtor 0x20010210
dtor 0x20010211
dtor 0x20010212
こんなくだらない話ですが、autoを使おうとするときって、型に対する意識が散漫になりませんか?
BOOST_FOREACH(auto x, hoge_vector) { ; }  // コピーされるよ
BOOST_FOREACH(auto &x, hoge_vector) { ; }
このループで変更を加えようとしている場合には、一時的に複製されたものを触っても何もおきなくて気づきます。しかし、読むだけの場合にはロジック上の不都合は起きないので、うっかりこのようなコードを埋め込んでしまうかも。
# boost 1.48.0にて確認

0 件のコメント:

コメントを投稿