加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – std :: deque的bug?

发布时间:2020-12-16 10:11:55 所属栏目:百科 来源:网络整理
导读:我试图使用循环和迭代器从双端队列中删除一个元素.我正在关注 online examples,但看到了一个错误. 我正在使用g(GCC)4.8.3 20140911(Red Hat 4.8.3-9). 这是代码: #include iostream#include dequeusing namespace std;// Display the contents of a queuevo
我试图使用循环和迭代器从双端队列中删除一个元素.我正在关注 online examples,但看到了一个错误.

我正在使用g(GCC)4.8.3 20140911(Red Hat 4.8.3-9).

这是代码:

#include <iostream>
#include <deque>

using namespace std;

// Display the contents of a queue
void disp_deque(deque<int>& deque) {
  cout << "deque contains: ";
  for (auto itr = deque.begin(); itr!=deque.end(); ++itr)
    cout << *itr << ' ';
  cout << 'n';
}

int main(int argc,char** argv) {
  deque<int> mydeque;

  // Put 10 integers in the deque.
  for (int i=1; i<=10; i++) mydeque.push_back(i);
  disp_deque(mydeque);

  auto it = mydeque.begin(); 
  while (it!=mydeque.end()) {
    cout << "Checking " << *it << ',';
    // Delete even numbered values.
    if ((*it % 2) == 0) {
      cout << "Deleting " << *it << 'n';
      mydeque.erase(it++);
      disp_deque(mydeque);
    } else ++it;
  }
}

这很简单 – 创建一个包含10个元素的列表并删除偶数元素.

请注意以下内容(不包括绒毛):

if ((*it % 2) == 0) {
  mydeque.erase(it++);
} else it++;

这是使用迭代器进行删除的推荐方法,这样您的迭代器就不会像上面的链接中提到的那样失效.

但是,当我运行它时,我得到以下内容:

$./test
deque contains: 1 2 3 4 5 6 7 8 9 10 
Checking 1,Checking 2,Deleting 2
deque contains: 1 3 4 5 6 7 8 9 10 
Checking 3,Checking 4,Deleting 4
deque contains: 1 3 5 6 7 8 9 10 
Checking 5,Checking 6,Deleting 6
deque contains: 1 3 5 7 8 9 10 
Checking 7,Checking 8,Deleting 8
deque contains: 1 3 5 7 9 10 
Checking 10,Deleting 10
deque contains: 1 3 5 7 9 
Checking 10,Deleting 10
deque contains: 1 3 5 7 
Checking 0,Deleting 0
deque contains: 1 3 5 
Checking 0,Deleting 0
deque contains: 1 3 
Checking 0,Deleting 0
deque contains: 1 
Checking 0,Deleting 0
deque contains: 
Checking 0,Deleting 0
Segmentation fault (core dumped)

看一看,它看起来很不错,直到删除8.实际上,数字9被完全跳过并且从未检查过!我期望应该发生的是:

$./test
deque contains: 1 2 3 4 5 6 7 8 9 10 
Checking 1,Deleting 8
deque contains: 1 3 5 7 9 10 
Checking 9,Checking 10,Deleting 10
deque contains: 1 3 5 7 9

事实上,这正是我将代码更改为此时所获得的:

if ((*it % 2) == 0) {
  it=mydeque.erase(it);
} else it++;

那么,为什么一种方法有效,而另一种方法无效?有人能解释一下吗?

即使我创建一个要删除的临时迭代器,我也会看到完全相同的问题输出:

while (it!=mydeque.end()) {
    cout << "Checking " << *it << ',';
    auto tmp_it = it++;
    // Delete even numbered values.
    if ((*tmp_it % 2) == 0) {
      cout << "Deleting " << *tmp_it << 'n';
      cout << "IT before delete: " << *it << 'n';
      mydeque.erase(tmp_it);
      cout << "IT after delete: " << *it << 'n';
      disp_deque(mydeque);
    } 
  }

在这里,我将它的副本存储在tmp_it中,然后递增它.我添加了一些调试语句,看到了一些非常奇怪的东西:

...
deque contains: 1 3 5 6 7 8 9 10 
Checking 5,Deleting 6
IT before delete: 7
IT after delete: 7
deque contains: 1 3 5 7 8 9 10 
Checking 7,Deleting 8
IT before delete: 9
IT after delete: 10
deque contains: 1 3 5 7 9 10 
Checking 10,Deleting 10
IT before delete: 10
IT after delete: 10
...

但是,删除元素8使其指向元素10,跳过9!在先前的删除中,它指向前一个元素(例如,当删除6时,它指向删除之前和之后的7).

我查看了deque的实现,并在“迭代器有效性”下看到了(强调我的):

Iterator validity If the erasure operation includes the last element
in the sequence,the end iterator and the iterators,pointers and
references referring to the erased elements are invalidated. If the
erasure includes the first element but not the last,only those
referring to the erased elements are invalidated. If it happens
anywhere else in the deque,all iterators,pointers and references
related to the container are invalidated.

那么这是否意味着在我的代码中,即使我在删除之前对其进行了后期增量,我的迭代器也会失效?即除了我删除的迭代器之外的迭代器是无效的?

如果是这样,那么它很好,但它似乎是一个鲜为人知的bug.这意味着在使用deque时,循环内的迭代器删除的common实现无效.

解决方法

您引用的代码仅用于关联容器(set,map等).

Scott Meyers的Effective STL第9项(恰当地命名为“在擦除选项中仔细选择”)显示了它是如何为序列容器(矢量,双端队列,字符串)完成的

for (SeqContainer<int>::iterator it = c.beqin(); it != c.end();) {
    if (predicate(*it)){
        it = c.erase(it); // keep it valid by assigning
    }                     // erase's return value to it
    else ++it;
}

这里,erase()返回值正是我们所需要的:它是一个擦除完成后,指向擦除元素后面的元素的有效迭代器.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读