0

マルチセットコンテナのイテレータのセットを別のデータ構造で維持しています。しばらくして、このデータ構造から1つのイテレーターを選択し、マルチセットからそのイテレーターに関連付けられた要素を消去します。私はこれを最初にこのようなものを使用します:

#include <iostream>
#include <set>

int main ()
{
  std::multiset<int> myints;
  std::cout << "0. size: " << myints.size() << '\n';

  for (int i=0; i<10; i++) myints.insert(i);
  std::cout << "1. size: " << myints.size() << '\n';

  myints.insert (5);
  std::cout << "2. size: " << myints.size() << '\n';

  std::multiset<int>::iterator it = myints.find(5);
  myints.erase (it);
  std::cout << "3. size: " << myints.size() << '\n';
  myints.erase (it);
  std::cout << "4. size: " << myints.size() << '\n';
  return 0;
}

ただし、2番目のmyints.erase (it);原因はセグメンテーション違反です。したがって、次のコードに変更して動作します。これが良い方法なのか、それとも実行可能なundefined状況なのか疑問に思いました。

int main ()
{
  std::multiset<int> myints;
  std::cout << "0. size: " << myints.size() << '\n';

  for (int i=0; i<10; i++) myints.insert(i);
  std::cout << "1. size: " << myints.size() << '\n';

  myints.insert (5);
  std::cout << "2. size: " << myints.size() << '\n';

  std::multiset<int>::iterator it = myints.find(5);
  myints.erase (it);
  std::cout << "3. size: " << myints.size() << '\n';

  std::multiset<int>::iterator newit = myints.find(*it);
  myints.erase (newit);
  std::cout << "4. size: " << myints.size() << '\n';

  return 0;
}
4

2 に答える 2

2

erase(it)イテレータを無効にしますit。つまり、その後は役に立たず、イテレータeraseを使用して何かを実行すると、未定義の動作が発生します。(おそらく、それが指している要素が消去されたときに、それが「次の要素に移動する」ことを期待していましたが、それはそれが行うことではありません。)

2番目のアプローチではこれは修正されません。たまたま動作するかもしれませitんが、消去した後も再利用しています。


編集:「マルチセットから5つだけを消去し、次の消去のために消去した後も有効に維持したい」という説明があれば、イテレータのコピーを作成し、元のコピーをインクリメントしてから、コピーを消去することでそれを行うことができます。

it = myints.find(5);
// better add a check here to make sure there actually is a 5 ...
std::multiset<int>::iterator newit = it;
it++;
myints.erase(newit);

すでにインクリメントitしているので、によって強制終了された要素を指していないため、有効なままですerase

しかし、正直なところ、これが実際に役立つ、あるいはむしろ必要とされる状況を想像することはできません。

于 2013-02-13T04:18:20.097 に答える
0

最初のアプローチでは、そのイテレータが指す要素を削除するとイテレータが無効になり、後で同じイテレータを使用して再度消去しようとすると、セグメンテーション違反が発生します。
2番目のアプローチでは、消去後に検索を実行するたびに、正しいイテレータが得られます。

コードに次の変更を加えることで、最初のケースを修正できます。ポストインクリメント演算子は新しいオブジェクトを返し、イテレータを次の位置に移動します。また、消去する前に終了チェックを行うことをお勧めします。そうしないと、未定義の動作が発生する可能性があります。

      std::multiset<int>::iterator it = myints.find(5);
      if(it != myints.end())
      myints.erase (it++);
      std::cout << "3. size: " << myints.size() << '\n';
      if(it != myints.end())
      myints.erase (it++);
      std::cout << "4. size: " << myints.size() << '\n';
于 2013-02-14T02:05:23.017 に答える