【问题标题】:Does a pointer become invalidated if an iterator is invalidated in STL containers如果迭代器在 STL 容器中失效,指针是否会失效
【发布时间】:2015-12-23 23:18:26
【问题描述】:

我试图理解向量中迭代器失效的概念。 从我所做的一些阅读中,我发现如果一个向量包含 7 个元素并且你删除了第 5 个索引上的元素,那么从第 5 个元素开始的迭代器就会失效。这是因为第 5 个索引之后的所有元素都需要向上移动一个插槽。这对我来说很有意义,但是我对以下两种情况有点困惑

    std::vector<foo> vec {foo{1},foo{2}};              //foo is a simple class
    foo* ptr = &vec[0];                                //Case 1
    std::vector<foo>::iterator it = vec.begin() + 1;   //Case 2

对于 STL 容器,如果迭代器失效,那么指针也会失效,这是否安全?例如,如果it 失效,ptr 也会失效吗?如果不是,您能否给出迭代器无效但指针仍然有效的情况?我目前对向量、地图和双端队列感兴趣。

更新: 所以我写了一点代码并进行了实验

std::vector<foo> vec {foo{1},foo{2},foo{3}};
foo* ptr = &vec[1];
std::vector<foo>::iterator it = vec.begin() + 1;
std::cout << "Before : " <<  ptr->a << "\n";
vec.erase(vec.begin() + 1); //Remove the second element
std::cout << "Iterator value : " << it->a << "\n";
std::cout << "After : " <<  ptr->a << "\n";

结果是

Before : 2
Iterator value : 3
After : 3

我很惊讶为什么向量没有提到迭代器无效,因为这是在删除元素之前获得的迭代器。

【问题讨论】:

  • 这些向量操作使向量中的所有指针、迭代器和对象引用无效
  • 您可以通过考虑容器必须如何管理其缓冲区、缓冲区或对象,并应用该标准旨在允许有效实施的规则来推断出大多数关于失效的规则。
  • Re 指针,标准使用短语“迭代器和引用”,对于任何实际解释都包括指针。这并不意味着所有这些指针都成为无效指针。擦除索引i 处的单个项目,指针&amp;v[i]&amp;v[i+1],直到并包括现在的最后一个项目,简单地引用具有可能更改值的对象(向上移动一个槽,正如你所说的那样)。向量的缓冲区保证是连续的,因此只要其中至少一个指针作为指针保持有效,其他(在新大小内)也必须作为指针有效。
  • @Cheersandhth.-Alf 这是否意味着如果我有一个指向总共有 3 个元素的容器中的第二个元素的指针,并且我还有一个指向第二个元素的迭代器。现在,如果我删除第二个元素,元素 2 和 3rd 的迭代器将变得无效,但是指针将简单地指向新元素(这将是 3rd)?
  • @JamesFranco:在正式的迂腐中你是对的,因为有可能创建一个不正当的vector 实现来跟踪迭代器并对它们做不圣洁的事情(它不能保持跟踪指针)。但在实践中,迭代器和指针是一样的。它们正式失效,这意味着它们不再指向具有与以前相同的值的对象,但它们仍然引用相同的对象。但是请注意,一个项目的erase 会导致该项目以前在最后被销毁。此类对象有特殊规则,已死但有存储。

标签: c++ pointers stl iterator


【解决方案1】:

当您移除一个项目时,不同的容器会有不同的表现。

来自http://en.cppreference.com

std::vector::erase

在擦除点或之后使迭代器和引用失效,包括end() 迭代器。

std::map::erase

对已擦除元素的引用和迭代器无效。其他引用和迭代器不受影响。

std::deque::erase

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

【讨论】:

  • 我刚刚更新了我的答案,你能告诉我为什么迭代器没有失效吗?
  • @JamesFranco,这是 UB 不幸的事情之一。有时代码的行为是理智的。但它在不同的编译器、不同的优化标志等中很容易有所不同。
  • UB 代表什么?
  • @JamesFranco:它做到了。但是,无论您在尝试使用无效的迭代器时所依赖的行为(您没有说那是什么),不要:当您违反合同并使用无效的迭代器时,任何事情都可能发生迭代器!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-19
  • 2023-01-13
  • 2013-05-30
  • 1970-01-01
  • 2017-10-05
相关资源
最近更新 更多