2016-07-16 21 views
2
#include<set> 
std::multiset<int>s; 
int main() { 
    s.insert(1); 
    s.insert(2); 
    s.insert(3); 
    for (auto i=s.rbegin();i!=s.rend();++i) { 
     auto j=s.lower_bound(*i<<1); 
     if (j!=s.end())s.erase(j); 
    } 
} 

このプログラムがクラッシュし、「マップ/イテレータをデクリメントできません」というエラーが表示されました。私はすべての要素が正の整数であると考えたので、*i<<1*iより大きくなるため、jの指し示された位置はiとは異なります。そして、referencestd :: multisetの要素を消去すると、無関係なイテレータが無効になりました

消去された要素への参照とイテレータは無効になります。その他の 参照とイテレータは影響を受けません。

iの指示位置以来

jjiとループには影響しません消去、異なっています。だから私はなぜそれが間違っているのか混乱している。

環境:Windows10のx86の、Visual Studioの2015 Update 3の

+2

「i!= j」を明示的に比較して、その特異性についてのあなたの推論が実際に保持されているかどうかを確認してください。 – Novelocrat

+1

@Novelocrat: 'i.base()!= j'は逆の反復子を扱っているからです。 – ildjarn

+0

@Novelocrat 'j!= s.end()'に '* i'と' * j'の出力を追加し、 '1 2'だけを期待通りに見ます。 – James

答えて

1

イテレータが無効である理由は、あなたのループがそれを消去し、そしてそれに続くfor反復がループの増分部分にその無効化されたイテレータを使用していることです。

デバッガを使用してこれを実行すると、erase()が呼び出されると、イテレータiがイテレータjと同じ要素を指していることがわかります。あなたは今やs.erase(j)になり、iも無効になります。ループの反復処理の++iでは、無効な反復子をインクリメントする試みが行われるため、エラーが発生します。

s.insert(1); 
s.insert(2); 
s.insert(3); 
for (auto i = s.rbegin(); i != s.rend(); 
    ++i) // <-- It's this that is causing the issue 
{ 
    auto j = s.lower_bound(*i << 1); 
    if (j != s.end()) 
     s.erase(j); // <-- If `i` is pointing to this element, iteration becomes invalidated 
} 

したがって、基本的には、存在しないものに++を実行しようとしています。 Visual Studioを使用しているので(エラーが発生しています)、デバッグ時にアセンブリウィンドウに移動すると、エラーが発生したのは実際には++の操作であることがわかります。


は、イテレータの無効化でこれを参照してください: multiset::eraseとのリンクで、この点に注意してください。消去要素へ

参考とイテレータが無効化されます。

関連する問題