2

マルチセットからすべての重複を出力したいのですが、どういうわけかイテレータが奇妙に動作します。このコードを修正するにはどうすればよいですか? このコードは永久ループを引き起こします。これには驚かされます。

#include <set>
#include <iostream>
#include <sstream>

static void print_duplicate(const std::multiset<int>& mset)
{
  std::stringstream error_msg;
  for (auto it = mset.begin(); it != mset.end(); ++it)
    {
      unsigned count = mset.count(*it);
      if (count < 2)
        continue;

      error_msg << "Duplicated numbers found:\n";

      for (unsigned i = 0; i < count; ++it, ++i)
        error_msg << "\tNum:" << *it << "\n";
    }

  std::cout << error_msg.str();
}

int main()
{
  std::multiset<int> mset;

  // fill it
  mset.insert(1);
  mset.insert(1);
  mset.insert(1);

  print_duplicate(mset);
}

EDIT サイクルの最後に --it を追加しました

  for (unsigned i = 0; i < count; ++it, ++i)
    error_msg << "\tNum:" << *it << "\n";
  --it; // this line fix it
}
4

5 に答える 5

3

外側のループ内では、it複数回インクリメントする場合があります。したがって、it != mset.end()最後がすでにスキップされているため、条件が真にならない可能性があります。末尾イテレータのインクリメントは未定義の動作です。つまり、サイレントに失敗する可能性もあります。

可能な解決策はit != mset.end()、内側のforループもチェックインすることです。

for (unsigned i = 0; (i < count) && (it != mset.end()); ++it, ++i)
    error_msg << "\tNum:" << *it << "\n";
于 2012-11-30T14:08:23.477 に答える
3

for (unsigned i = 0; i < count; ++it, ++i)このループが終了すると、itに等しくなり、メインループからmset.end()のもう一方がまだ残っているため、別のものを取得しているため、プログラムは終了しません。++itmset.end()

于 2012-11-30T14:08:32.527 に答える
2

問題は、それを検出せずに最後をすり抜けてしまうことのようです。あなたが創るには、 smsetしかありませ1ん。これはcount3 になることを意味し、ネストされたfor( 上の 1 つi) は 3 回実行されます。終了すると、itに等しくなりmset.end()ます。forその後、コントロールはアウターの終わりに到達し、itインクリメントされ、不正になり、さらに重要なことに、 とは異なりmset.end()ます。つまり、外側のループは決して終了しません。

于 2012-11-30T14:08:33.787 に答える
1

簡単な修正: 内側のループの後に余分な行を追加します: it--;

理由は Angew's answer で説明されています。

于 2012-11-30T14:19:28.567 に答える
0

for ループを次のように変更します。

for(std::container::iterator it=mset.begin(), it_next=it; it!=mset.end(); it=it_next) {
  ++it_next;
  ...
}

基本的に、反復子に対して変数をチェックしているため、ループの終わりをスキップしています。2 番目の反復子のみをインクリメントすると、これが発生しなくなります。

于 2012-11-30T14:11:17.593 に答える