最近、C++の新しい機能について勉強しているのですが、
タイトルの件についてよく理解できない挙動があります。
以下の擬似コードについて
-----------------
int i, count = 0;
list<int> vt;
list<int>::iterator itr, last;
for (i = 0; i < 10; ++i) vt.push_back(i);
for (itr = vt.begin(); itr != vt.end(); ++itr) wcout << *itr << L, ;
wcout << endl;
last = remove_if(vt.begin(), vt.end(),
[count] (int n) mutable { return ++count == 5; });
vt.erase(last, vt.end());
for (itr = vt.begin(); itr != vt.end(); ++itr) wcout << *itr << L, ;
wcout << endl;
-----------------
私として、5番目の要素を削除する意図があるのですが、
実際に出力される結果は以下のとおりです。
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 5, 6, 7, 8,
「4」に加えて「9」まで削除されてしまいます。
これはなぜなのでしょうか?
ちなみに、mutableを使用せずに、以下のような参照形式にすると期待通りの
結果になります。
last = remove_if(vt.begin(), vt.end(),
[&count] (int n) { return ++count == 5; });
「mutable」と「参照形式」によるキャプチャーでは何が違うのでしょうか?
この現象に関して言うなら lambda は無関係だ。
提示の *理解困難な挙動* の原因は remove_if のほうにある。
上記のコードが「プログラマの勝手な期待通り」に動くには、
アルゴリズム関数内で関数オブジェクトがコピーされてはならないわけだ。
それは迷信。
http://www.kijineko.co.jp/tech/superstitions/functor-is-not-copied-in-
algorithm.html
[&] の場合は、値が変更されるのは元の count であるから、
lambda 関数オブジェクトがコピーされても、されなくても、結果は同じ。
[=] の場合は、関数オブジェクトの初期化の際に
lambda 内部に count のコピーである別の変数が作られる。
値が変更されるのはそのコピーされた別の変数 (初期値 count) であるわけだ。
remove_if 中に関数オブジェクトがコピーされると [&] とは違う結果になる。
ラムダ式のオブジェクトがコピーされていたんですね。
理由が分かって安心しました。
アドバイスありがとうございました。