c++ 迭代器失效

92dk7w1h  于 2023-01-14  发布在  其他
关注(0)|答案(5)|浏览(123)

嗨,我在C++初级读本中读到,向向量添加元素会使迭代器失效。我不明白为什么删除元素不会使它们失效,因为下面的代码是有效的

std::vector<int> a = {1,2,3,4,5,6};

auto b = a.begin();

while (b != a.end()){
    
    if (*b%2 != 0)
        a.erase(b);
    else
        b++;
}

注意:此代码来自C++引物本身和cpp reference

0yycz8jy

0yycz8jy1#

实际上这不是问题的答案,但我认为值得一提的是,在现代C++中,你应该通过使用算法和基于范围的for循环来避免迭代器。

std::vector<int> a = {1,2,3,4,5,6};
std::erase_if(a, [](int x) { return x%2 != 0; });
o8x7eapl

o8x7eapl2#

一般来说,此代码片段

auto b = a.begin();

while (b != a.end()){
    
    if (*b%2 != 0)
        a.erase(b);
    else
        b++;
}

是无效的。它之所以有效是因为容器std::vector满足连续范围的概念。如果不使用vector,而是使用例如std::list<int>,则迭代器b将无效。
应该这样写

auto b = a.begin();

while (b != a.end()){
    
    if (*b%2 != 0)
        b = a.erase(b);
    else
        b++;
}
n53p2ov0

n53p2ov03#

常见用法。来自cppreference:(erase)'使擦除点或擦除点之后的迭代器和引用无效,包括end()迭代器。
还有人指出应该这样写:

#include <vector>

std::vector<int> vec = { 1, 2, 3, 4 };

for (auto it = vec.begin(); it != vec.end(); )
{
    if (*it % 2 != 0)
    {
        it = vec.erase(it);
    }
    else
    {
       ++it;
    }
}

如果用户更喜欢“while”而不是“for”,请进行调整。如果性能是最重要的,则可以从末尾开始,但这可能不太适合缓存。
编辑:代码片段字面上是cppreference链接。

jyztefdp

jyztefdp4#

向向量添加元素可能会导致向量完全重新分配,这会使之前持有的所有迭代器失效。
如果删除向量的一个条目,则erase方法返回:a)到下一个有效元素的迭代器B)结束迭代器。
但你必须使用它。在你的情况下:

b = a.erase(b);
tjrkku2a

tjrkku2a5#

正如许多人指出的那样,它是偶然工作的。不要在生产中这样做。迭代器被设计成尽可能轻量级的,这样就不会有一个标志说它是无效的。那将是太浪费了。
std::vector迭代器可能被实现为带有一些辅助函数的指针。删除一个元素将移动所有元素,以便相同的指针现在指向旧元素所在的新元素。它之所以有效,是因为元素存储在连续的内存中,没有间隙。

相关问题