如果我们采用这个例子:
std::map<int,foo*> intmap;
fillMap(intmap);
// I will force this to end(), in real life this could be a "find" output
std::map<int,foo*>::iterator iter = intmap.end();
if(iter->second != 0)
iter->second->whatever();
我遇到了分段错误(这是预期的,例子不是检查“iter!= intmap.end()” 故意)在“whatever()”调用但不在“ - &gt;第二个”空指针检查上:它是预期的行为吗?这个seg会在“whatever()”调用上系统地出错,还是依赖于特定的运行时内存条件?
提前感谢您的意见。 贾科莫
答案 0 :(得分:6)
解除引用STL容器的end()
和过去的迭代器是未定义的行为。您无法调用预期。一切都可以发生,甚至可以发挥作用。
它可能取决于很多因素,如编译器/库/操作系统版本,运行时环境状态,调试/发布版本等。所以你永远不应该假设如果你做了禁止的东西会发生什么。
答案 1 :(得分:0)
您无法取消引用“结束”迭代器。请注意,iter->
与(*iter).
大致相同;也就是说,有一个解除引用。
答案 2 :(得分:0)
解除引用end()
迭代器是一种未定义的行为。它可能会也可能不会崩溃。
您必须像这样检查find
的返回值:
if(iter != intmap.end())
iter->second->whatever();
答案 3 :(得分:0)
取消引用过去的迭代器的结果当然是未定义的行为,所以不能保证它会做什么。
然而,考虑可能发生的事情可能具有指导意义(并且在调试方案中很有用)。关联容器的典型实现是作为节点的二叉树,其中每个节点包含以迭代顺序指向next
和previous
节点的指针,并且迭代器是指向节点的指针周围的薄包装器。类似地,list
被实现为双链表,其中每个节点包含指向next
和previous
节点的指针。由于过去的迭代器需要是可递减的,因此最简单的实现是指向一个始终存在的节点,其previous
指针指向容器中的最后一个节点。
因为这个过去的终端节点总是需要存在,即使是空容器,最简单的实现是将它放在容器类本身,大多数库实现都会这样做。因此,它的存储是自动(函数本地)存储,并且它将是默认构造的,因此解除引用过去的迭代器将给堆栈垃圾。
我们可以通过比较指针来检查:
#include <map>
#include <iostream>
int main() {
std::map<int, int> m;
std::cout << &m << ' ' << &*m.end() << ' ' << &m + 1 << '\n';
}
0xbf990034 0xbf990048 0xbf99004c
如您所见,过去端节点的存储包含在map
的堆栈占用空间内。