remove_if使えよと言われればそれまでですが普段使う感じだとループ中に消したりする事が多いので…
vector
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
vector<int>::iterator it = v.begin();
while (it != v.end()) {
if (*it == 20) {
it = v.erase(it);
} else ++it;
}
it = v.begin();
while (it != v.end()) {
cout << *it << endl;
++it;
}
deque
deque<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
deque<int>::iterator it = v.begin();
while (it != v.end()) {
if (*it == 20) {
it = v.erase(it);
} else ++it;
}
it = v.begin();
while (it != v.end()) {
cout << *it << endl;
++it;
}
list
list<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
list<int>::iterator it = v.begin();
while (it != v.end()) {
if (*it == 20) {
it = v.erase(it);
} else ++it;
}
it = v.begin();
while (it != v.end()) {
cout << *it << endl;
++it;
}
map
map<int, int> v;
v[10] = 10;
v[20] = 20;
v[30] = 30;
map<int, int>::iterator it = v.begin();
while (it != v.end()) {
if (it->second == 20) {
v.erase(it++);
} else ++it;
}
it = v.begin();
while (it != v.end()) {
cout << it->first << " " << it->second << endl;
++it;
}
multimap
multimap<int, int> v;
v.insert(make_pair(10, 10));
v.insert(make_pair(20, 20));
v.insert(make_pair(30, 30));
multimap<int, int>::iterator it = v.begin();
while (it != v.end()) {
if (it->second == 20) {
v.erase(it++);
} else ++it;
}
it = v.begin();
while (it != v.end()) {
cout << it->first << " " << it->second << endl;
++it;
}
set
set<int> v;
v.insert(10);
v.insert(20);
v.insert(30);
set<int>::iterator it = v.begin();
while (it != v.end()) {
if (*it == 20) {
v.erase(it++);
} else ++it;
}
it = v.begin();
while (it != v.end()) {
cout << *it << endl;
++it;
}
とここまでやったけどmultisetとかは多分同じなので以下略…。。。
おおまかにvectorとかdequeとかシーケンスコンテナと呼ばれる奴はeraseの帰り値にイテレーターを返すのでそれが次のイテレーターになる。
mapとかsetとかは連想コンテナと言われる奴っぽく、eraseしたイテレーターは無効なアドレスを察すらしいので、 it++
を渡してイテレーターのコピーをしつつ要素を削除、かつイテレーターを勧める → コピーされたイテレーターを使って連想コンテナの要素を削除 というノウハウがあるらしい ここがわかりやすかった
たしかにこんな感じのコードを書くと違うっぽい。イテレーターの中身が書き変わってる。
cout << "OK" << endl;
{
set<int> v;
v.insert(10);
v.insert(20);
v.insert(30);
set<int>::iterator it = v.begin();
while (it != v.end()) {
cout << *it << endl;
if (*it == 20) {
v.erase(it++);
} else ++it;
}
}
cout << endl;
cout << "NG" << endl;
{
set<int> v;
v.insert(10);
v.insert(20);
v.insert(30);
set<int>::iterator it = v.begin();
while (it != v.end()) {
cout << *it << endl;
if (*it == 20) {
v.erase(it);
}
it++;
}
}
まとめ
多分eraseでイテレーターが帰ってきたら it = v.erase(it);
で、voidだったら if (XXX) { v.erase(++it); } else it++;
で、みたいな感じの覚え方でざっくり大丈夫
全然気にしたことなかったけど各所でイテレーターとかループ回す時は前++のほうが効率がいいって書いてあるのでこれから気をつけます