2

ベクトルをデバッグしているときに、矛盾が見られます。要素が 1 つしかないベクトルからエントリを削除しようとする次のコードを想定します。

#include <iostream>
#include <vector>
std::vector<int> v;
void myremove(int);
int main()
{
  v.push_back(10); 
  std::cout << "10 pushed back\n";
  myremove(10);
  std::cout << "done :)\n";
  return 0;
}

void myremove( int a )
{
  std::vector<int>::iterator it = v.begin();
  int counter = 0;
  for ( ; it != v.end(); it++ ) {
    std::cout << "iterating for " << counter << " times and vector size is " << v.size() << "\n";
    if ( a == (*it) ) {
      v.erase(it);
      std::cout << "removed " << a << "\n";
    }
    ++counter; 
  }
}

これは、出力に表示されるものです。

 $ g++ test.cpp 
 $ ./a.out | more
 10 pushed back
 iterating for 0 times and vector size is 1
 removed 10
 iterating for 1 times and vector size is 0
 iterating for 2 times and vector size is 0
 iterating for 3 times and vector size is 0
 iterating for 4 times and vector size is 0
 iterating for 5 times and vector size is 0
 iterating for 6 times and vector size is 0
 ....
 ....
 iterating for 33790 times and vector size is 0
 Segmentation fault

私が理解しているのは、要素が削除されるとサイズが0になるということですが、イテレータは1ステップ移動し、それでも最後に到達しようとしますが、彼はすでに終点を通過したことを知りません。

誰かが何が起こっているのか、それを回避する方法をもっと説明できますか?

4

6 に答える 6

6

erase()イテレータの呼び出しitが無効になった後:

消去された要素への反復子と参照、およびそれらの間の要素とコンテナーの末尾への参照は無効になります。

it代わりに の戻り値に設定し、erase()削除が発生しなかった場合にのみインクリメントします。

while (it != v.end())
{
    if ( a == (*it) )
    {
        it = v.erase(it);
        std::cout << "removed " << a << "\n";
    }
    else
    {
        ++it;
    }
}

の戻り値erase()は次のとおりです。

最後に削除された要素に続く反復子。

std::remove_if()ループを手動でコーディングして要素を消去する代わりに、次のように使用できます。

v.erase(std::remove_if(v.begin(),
                       v.end(),
                       [](const int i) { return i == 10; }),
        v.end());
于 2013-04-12T14:21:29.903 に答える
4

消すと

v.erase(it);

あなたのイテレータはもう有効ではありません。消去から返されたイテレータを使用する必要があります。Erase は、呼び出しによって消去された要素の次の要素を指す反復子を提供します。また、ループがインクリメントされる前に最後の要素を消去した場合は、ループを中断する必要がありますit

it = v.erase(it);
if(it == v.end())
    break;

提案: for ループを while ループに変更できます。そして、イテレータを明示的にインクリメントします(つまり、何も消去していない場合のみ。消去した場合、イテレータはすでにインクリメントされています)。

このような

while(it != v.end()) {
    if ( a == (*it) ) 
      it = v.erase(it);
    else
      ++it; 
}
于 2013-04-12T14:21:20.977 に答える
0

すべての挿入と消去は、コンテナーのすべての反復子を無効にします。メソッドは、挿入/消去後に唯一の有効な反復子を返します。

于 2013-04-12T14:21:19.730 に答える
0

消去関数を呼び出すと、反復子は有効な反復子ではなくなり、無効な反復子をインクリメントすると、誤った結果が得られます。

于 2013-04-12T14:23:01.007 に答える