[[Hirofumi Fujii Start Page]]

C++ の std::list で久々に原因究明に半日を要した bug を書いてしまった。
線形 list の途中から先を最後尾から削除するのに、


 	std::list<MyClass> store;
 	std::list<MyClass>::iterator itcur;
 
 		:
 
 	std::list<MyClass>::iterator it = store.end();
 	--it;
 	while(it != itcur)
 	{
 		store.pop_back(); --it;
 	}
 

みたいなコードを書いてしまった。itcur は現在地を示して
いる iterator で、最後尾(end() の一つ前)から消していって、
現在地まで来たらやめる(現在地は残す)つもりのコードである。
ものの見事にアクセス違反で落ちるコードである。--it を
最後に持ってきているのは、消す前に it を使って、消す要素の
情報にアクセスしているからで、そうでなければ while 文中で
it-- として、bug にはならなかった。そうでなくても、
 
 	while(it != itcur)
 	{
 		--it; store.pop_back();
 	}
 
としていれば、bug にはならない。

ここまで書けば理由はわかるだろう。

pop_back の時点で it が無効になっているからで、list を普通に
考えて実装すれば iterator の指し示す要素の中に次要素と
前要素の iterator(pointer) を格納しておくだろう。
ところが、その要素そのものが消えているので、++ も -- も、
もはや無効というわけである。

pop_back() が it の ++ や -- に作用するなどというのは、コードを
見ただけではなかなか読み取れない。erase() を使えばという意見も
あるかも知れないが、似たようなものだと思う。なぜなら、erase() を
使って書き換えてみたのだが、気がつかなかった。単に私が馬鹿だと
いう意見なら、その通り。

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS