在迭代std :: deque时擦除元素时出现分段错误

时间:2016-05-27 06:20:12

标签: c++ iterator deque erase

为什么以下代码崩溃?当我通过反向迭代器进行迭代时,我该怎么办?我如何删除单个元素?

deque q;
q.push_back(4);
q.push_back(41);
q.push_back(14);

for (auto it = q.begin(); it != q.end();) {
    auto current = it;
    q.erase(current);
    it++; 
}

4 个答案:

答案 0 :(得分:3)

  
      
  1. 为什么以下代码崩溃?我如何删除单个元素?
  2.   

std::deque::erase使迭代器无效。

  

除非擦除的元素位于容器的末尾或开头,否则所有迭代器和引用都将失效,在这种情况下,只有迭代器和对擦除元素的引用才会失效。

     

除非擦除的元素位于容器的开头且最后一个元素未被擦除,否则过去的迭代器也会失效。

在您的代码中,要删除的元素(即itcurrent)的迭代器将在q.erase(current)后变为无效,然后it++将导致UB。

您可以使用std::deque::erase

的返回值
  

跟随最后删除的元素的迭代器。如果迭代器pos引用最后一个元素,则返回end()迭代器。

for (auto it = q.begin(); it!=q.end(); )
{
    it = q.erase(it);
}
  
      
  1. 如果我通过反向迭代器进行迭代,我该怎么办。
  2.   

由于std::deque::erase不接受reverse_iterator作为参数,因此您需要使用base()将其转换为普通迭代器(注意位置转换)。如

for (auto it = q.rbegin(); it!=q.rend(); )
{
    it = std::make_reverse_iterator(q.erase((++it).base()));
}

答案 1 :(得分:2)

根据C++11 23.3.3.4 deque modifiers /4,如果删除某些元素,deque迭代器将无效。

  

擦除deque的最后一个元素的擦除操作只会使过去的迭代器和所有迭代器以及对擦除元素的引用无效。

     

擦除双端队列的第一个元素而不是最后一个元素的擦除操作仅使擦除的元素无效。

     

擦除操作既不擦除deque的第一个元素也不擦除deque的最后一个元素,使过去的迭代器和所有迭代器以及对deque的所有元素的引用无效。

在您的情况下,您通常只会擦除第一个元素,因此它只会使该元素无效。这意味着it++无效,您应该使用以下内容:

it = q.erase(it);

在循环内部,因为erase调用本身返回一个“已调整”的迭代器。删除最后一个元素时也可以这样做。

但是,由于你的代码完全清除了列表(假设它不是需要处理每个元素的东西的缩减版本),你可以完全放弃循环并使用:

q.clear();

答案 2 :(得分:1)

正如其他回答者已经指出的那样,从队列中删除元素将使用于迭代其元素的迭代器无效。因此失败了。

但我认为你不打算删除队列中的所有元素,在这种情况下你可能会更喜欢使用:

q.erase(q.begin(), q.end());

q.clear();

因此,我建议使用另一种技术,可用于从队列中删除符合特定条件的项目:NavigationCacheMode

此处,函数std::remove(...)std::remove_if(...)用于将要删除的项目(匹配特定条件)移动到容器的末尾。然后使用基于范围的q.erase(...)版本来删除项目。

以下是一个例子:

#include <deque>
#include <algorithm>
#include <iostream>

// predicate function for removal of elements
bool greater_three(int x) {
    return x > 3;
}

int main() {
    std::deque<int> q = {1,2,3,4,5};
    for (auto i : q) std::cout << i << " "; std::cout << "\n";
    // delete all items with value 3
    q.erase(std::remove(q.begin(), q.end(), 3), q.end()); 
    for (auto i : q) std::cout << i << " "; std::cout << "\n";
    // delete all items with value > 3
    q.erase(std::remove_if(q.begin(), q.end(), greater_three), q.end()); 
    for (auto i : q) std::cout << i << " "; std::cout << "\n";
}

输出结果为:

$ g++ test.cc -std=c++11 && ./a.out
1 2 3 4 5 
1 2 4 5 
1 2 

供参考:

答案 3 :(得分:0)

显然不支持在迭代元素时删除元素。