[Windows] std::listをiteratorで探索中に要素を削除するとき

listをiteratorでたどりながらeraseで要素を削除すると、削除された要素が無効になる。そのためiteratorは別の有効な要素をささねばならない。
stackoverflow.comに投稿されたこの質問への答えは
Can you remove elements from a std::list while iterating through it?

items.erase(i++); // alternatively, i = items.erase(i);

とする、というもの。これについてコメント欄で「i++でもおかしくならないか」、などやり取りされているのも楽しい。
eraseされたiteratorは無効になり、eraseは次の有効はiteratorを指す。最後の要素を削除したときは、end()と等しい値になる。

手元にある professional c++の説明では、vector::eraseではiteratorの値に注意しなければならないので、remove-erase-idiomを使うのがいい、とあった。
しかし、本にあるソースコードをVS2012で使おうとすると使えなかった。
本にあったコードは以下。

void removeEmptyStrings(vector<string>& strings)
{
    auto it = remove_if(strings.begin(), strings.end(),
    [](const string& str){return str.empty();});
    // Erase the removed elements.
    strings.erase(it, strings.end());
}

ところが、VS2012ではvectorにremove_ifがない。vector::eraseの動きはlist::eraseと同様だ。戻り値はeraseされた要素の直後の要素になる。後ろにないときはend()と同等。

eraseのみで削除する場合は、for loopを使うと以下のようになるのではないか。

	for (auto it = strings.begin();
		it != strings.end();
		it++)
	{
		if (it->empty())
			it = strings.erase(it);
		if (it == strings.end())
			break;
	}

広告

コメントを残す

コメントを投稿するには、以下のいずれかでログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。