[英]c++ vector erase advances iterator
以下简化代码有效,因为它删除了所有矢量元素。 但是,我不明白为什么。 由于f.erase(r)
没有捕获返回的值,这将是新的迭代器值,并且没有其他迭代器增量器,并且根据文档, erase(iterator position)
参数不是通过引用传递的,迭代器在哪里进阶?
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> f = {1,2,3,4,5};
auto r = f.begin();
while (r != f.end())
{
std::cout << "Erasing " << *r << std::endl;
f.erase(r);
}
return 0;
}
迭代器在哪里得到高级?
迭代器没有得到高级。 您的代码似乎工作的事实只是偶然,实际上您有未定义的行为。
从std::vector::erase
上的cppreference :
在擦除点处或之后使迭代器和引用无效,包括 end() 迭代器。
调用f.erase(r);
后不允许使用r
; . 如果你这样做,有趣的事情就会发生。
你必须写
while (r != f.end())
{
std::cout << "Erasing " << *r << std::endl;
r = f.erase(r);
^^^^^^^^^^^^^^^^
}
因为擦除后迭代器变得无效。
或者你可以写
f.clear();
因为循环删除了向量的所有元素。
考虑到迭代器 r 仅在循环中使用,因此最好在使用它的循环的 scope 中声明它。 例如
for ( auto r = f.begin(); r != f.end(); )
{
std::cout << "Erasing " << *r << std::endl;
r = f.erase(r);
}
迭代器在哪里得到高级?
它没有,迭代器一直指向同一个位置。 这在技术上是未定义的行为,但如果您考虑一下循环实际上在做什么,您就会明白为什么会得到“正确”的结果。
您的向量包含一个指向它存储的对象的指针。 您的迭代器将指向 memory 与您想要的元素的偏移量。 在这种情况下,它将指向数据的开头。 当您擦除第一个元素时,迭代器无效,但它仍指向向量的开头。 erase
将所有元素向前移动,因此当您将 go 进入下一次迭代时,您在与第一次迭代中相同的 state 中,除了向量小一个元素。 您反复执行此操作,直到没有剩余元素和end() == begin()
不过,您不应该依赖这种情况总是发生,而只需使用clear()
从向量中删除所有元素。
在大多数情况下(包括erase())在向量中添加/删除元素会使引用和迭代器无效。 使用旧的迭代器会导致未定义的行为。
正如@Nathan 在评论中提到的那样, f.clear()
就是您所需要的。
并根据文件,
你应该读到最后:
因为向量使用数组作为其底层存储,擦除除向量末端以外的位置的元素会导致容器将擦除段后的所有元素重新定位到它们的新位置。 与其他类型的序列容器(例如list或forward_list )为相同操作执行的操作相比,这通常是一种低效的操作。
和
返回值
指向由 function 调用擦除的最后一个元素之后的元素的新位置的迭代器。 如果操作擦除了序列中的最后一个元素,则这是容器端。
最后:
迭代器有效性
指向position (或first )及以后的迭代器、指针和引用无效,所有迭代器、指针和指向position (或first )之前的元素的引用都保证继续引用它们在调用之前引用的相同元素。
erase
使r
无效。 之后取消引用r
会导致未定义的行为。
但在现实世界中,除非实现有意检查迭代器的有效性,否则它不会引起任何问题。
vector
迭代器通常只存储指向元素的指针。 当你删除一个元素时,它右边的所有元素都会向左移动一个 position。 因此,以前被删除元素占用的 memory 位置将被下一个元素占用。
将迭代器传递给erase
会使该迭代器无效,因此进一步使用它(在下一次迭代中将其传递给erase
时)具有未定义的行为。 因此,该程序实际上并没有“工作”。 它可能看起来有效,因为这是一种可能的行为。 但不能保证这种行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.