C ++中非const列表迭代器的奇怪行为

时间:2012-09-17 12:18:03

标签: c++ list iterator segmentation-fault erase

我有一个代码:

it = tableAndHand.begin();
while(++it != tableAndHand.end()) {
 if(*it == *(--it)) {
  ++cardCount;
  ++it;
 } else {
  cardCounts1.insert(pair<int,int>(cardCount,*it));
  while(cardCount > 1) {
   it = tableAndHand.erase(--it);
   --cardCount;
  }
 ++it;
 }
}
cardCounts1.insert(pair<int,int>(cardCount,*(--it)));
while(cardCount > 1) {
 it = tableAndHand.erase(--it);
 --cardCount;
}

tableAndHand是一个开始时7个值的列表,在删除一些值后,我在那个有问题的地方得到了分段错误,为什么会这样?

列表中的值被排序,并且它在列表{0,0,0,1,1,2,2}上失败,在某处迭代1s(在正确擦除2 0之后,因此列表的大小已经是5)。

我只是想将唯一值的计数保存到map card1中,并从列表中删除重复的值,我的算法出了什么问题?

编辑:看起来问题是(* it == *( - it))没有从左到右评估,虽然我在cplusplus.com上关于运营商的文章中找不到“==”的评价在其他一些网站上,他们说它是从左到右进行评估的。关于它的一些很好的联系?

EDIT2:好的,它有效,我忘了将tableAndHand.erase( - it)迭代器分配给它,现在它完美而快速地工作:)

3 个答案:

答案 0 :(得分:3)

在循环中将it最多增加三次,然后再与结束进行比较。

擦除而不保存新的迭代器。

很多副作用。

if(*it == *(--it)) {的排序尚未定义,因此您最终可能会将元素与自身进行比较。 (==不是序列点,因此可以按任意顺序评估*it*(--it)

您没有检查tableAndHand是否为空 - 您在检查之前会增加it

答案 1 :(得分:1)

在循环的每次迭代中增加it两次:

while(++it != tableAndHand.end()) {  // <---- IN THIS LINE
  //HERE IS THE PROBLEM
  if(*it == *(--it)) {
   ++cardCount;
   ++it;      // <----- AND EITHER HERE
  } else {
    cardCounts1.insert(pair<int,int>(cardCount,*it));
    while(cardCount > 1) {
     tableAndHand.erase(--it);
     --cardCount;
    }
    ++it;   // <----- OR HERE
  }
}

这意味着你应该超出列表末尾,并在while循环中进行比较:

while (++it != tableAndHand.end())

永远产生真,因为迭代器永远不会指向容器的末尾完全

如果元素的数量是偶数, 可以工作(尽管,因为你有时会删除元素,所以很难预测)。


另一个问题是,初始迭代将立即递增it一次,如果容器恰好为空,则立即将其推送到容器的末尾。

答案 2 :(得分:1)

if(*it == *(--it))

此代码的行为未指定:编译器可以在比较的右侧评估--it,然后评估左侧的it,或者它可以执行它们反过来说。

更一般地说,对于列表,不要尝试使用相同的迭代器来访问两个相邻的元素;它只会导致令人困惑的代码。使用两个迭代器:当前位置和尾部,每次递增一次,每次循环时只递增一次。