结束迭代器和分割故障

end iterator and segmentation fault

本文关键字:故障 分割 迭代器 结束      更新时间:2023-10-16

如果以此示例为例:

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()" 是故意的)在" whywhing()"呼叫上,但在" -> second" null指针检查:这是预期的行为吗?此seg故障会系统地在" whywhing()"调用上,还是取决于特定的运行时间内存条件?

事先感谢您的评论。giacomo

删除end()和STL容器的前端迭代器是未定义的行为。您没有什么可以称呼预期的。一切都会发生,甚至可以起作用。它可能取决于很多因素,例如编译器/libs/os版本,运行时环境状态,调试/发布构建等。因此,您永远不应该假设如果您做肮脏的事情会发生什么。

您不能取消"结束"迭代器。请记住,iter->(*iter).大致相同;也就是说,有一个解雇。

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

您必须检查find的返回值:

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

删除过去迭代器的结果当然是不确定的,因此不能保证它会做什么。

但是,考虑可能发生的事情可能具有启发性(在调试场景中很有用)。关联容器的典型实现是作为节点的二进制树,每个节点在迭代顺序中包含指向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的堆栈足迹中。