9

此循环在运行时更改迭代器:

std::vector<int> c;
c.push_back(1);
c.push_back(2);

std::vector<int>::iterator iter    = c.begin();
std::vector<int>::iterator endIter = c.end();

while( iter != endIter )
{
    std::cout << (*iter) << std::endl;
    iter = c.erase(iter);
}

它不起作用,因为:

迭代器和对已擦除元素以及它们与容器末端之间的元素的引用无效。Past-the-end迭代器也无效

我怎样才能重写它(不使用std::list, 并使用while循环)?

顺便说一句,我知道这auto是从 C++11 开始实现的。为什么使用它会有好处?

4

4 回答 4

22

只需不要缓存将失效的结束迭代器:

while( iter != c.end() )
{
    std::cout << (*iter) << std::endl;
    iter = c.erase(iter);
}

或打印后清除矢量:

for(const auto& i : c) {
    std::cout << i << std::endl;
}
c.clear();
于 2013-06-17T17:21:12.880 回答
12

擦除元素会发生变化end()。改变循环:

while( iter != c.end())
于 2013-06-17T17:21:00.943 回答
7

任何一个

  • 重写为

    while( iter != c.end() )
    {
        std::cout << (*iter) << std::endl;
        iter = c.erase(iter);
    }
    

    并且代码将不再依赖任何可能失效的迭代器,

或者

  • 在每次失效操作后“刷新”任何可能失效的迭代器

    while( iter != endIter )
    {
        std::cout << (*iter) << std::endl;
        iter = c.erase(iter);
        endIter = c.end();
    }
    

这是在这种情况下通常使用的两种通用方法。

于 2013-06-17T17:21:56.313 回答
3

这样做的一种更惯用的方式......

while(c.begin() != c.end()) c.erase(c.begin());

虽然这很慢,但作为底层实现的向量使用了一个连续的数组(最后有额外的空间)。所以反复擦除开始元素是非常低效的,因为每个元素最终都被提前复制到数组中的一个空格,n - 索引时间!您可以通过执行以下操作从根本上提高性能:

while(c.begin() != c.end()) c.pop_back();
于 2013-06-17T17:24:02.113 回答