结束迭代器和分段错误

时间:2012-10-24 15:38:17

标签: c++ unix iterator segmentation-fault

如果我们采用这个例子:

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()”调用上系统地出错,还是依赖于特定的运行时内存条件?

提前感谢您的意见。 贾科莫

4 个答案:

答案 0 :(得分:6)

解除引用STL容器的end()和过去的迭代器是未定义的行为。您无法调用预期。一切都可以发生,甚至可以发挥作用。 它可能取决于很多因素,如编译器/库/操作系统版本,运行时环境状态,调试/发布版本等。所以你永远不应该假设如果你做了禁止的东西会发生什么。

答案 1 :(得分:0)

您无法取消引用“结束”迭代器。请注意,iter->(*iter).大致相同;也就是说,有一个解除引用。

答案 2 :(得分:0)

解除引用end()迭代器是一种未定义的行为。它可能会也可能不会崩溃。

您必须像这样检查find的返回值:

if(iter != intmap.end())
   iter->second->whatever();

答案 3 :(得分:0)

取消引用过去的迭代器的结果当然是未定义的行为,所以不能保证它会做什么。

然而,考虑可能发生的事情可能具有指导意义(并且在调试方案中很有用)。关联容器的典型实现是作为节点的二叉树,其中每个节点包含以迭代顺序指向nextprevious节点的指针,并且迭代器是指向节点的指针周围的薄包装器。类似地,list被实现为双链表,其中每个节点包含指向nextprevious节点的指针。由于过去的迭代器需要是可递减的,因此最简单的实现是指向一个始终存在的节点,其previous指针指向容器中的最后一个节点。

因为这个过去的终端节点总是需要存在,即使是空容器,最简单的实现是将它放在容器类本身,大多数库实现都会这样做。因此,它的存储是自动(函数本地)存储,并且它将是默认构造的,因此解除引用过去的迭代器将给堆栈垃圾。

我们可以通过比较指针来检查:

#include <map>
#include <iostream>
int main() {
    std::map<int, int> m;
    std::cout << &m << ' ' << &*m.end() << ' ' << &m + 1 << '\n';
}

0xbf990034 0xbf990048 0xbf99004c

如您所见,过去端节点的存储包含在map的堆栈占用空间内。