我有一个导致上述行为的最小代码:
vector<int> result(9);
int count = 0;
cout << "test1n"; // removing this line causes 'core dump'
for (int j=0; j < 12; j++)
result[count++] = 1;
cout << "test2n";
result是一个大小为9的向量,在"for"循环中,我正在访问超出范围的元素。
现在,删除test1行,代码运行时没有任何错误;但有了这条cout线,我得到了
*中出现错误/out_of_range_vector2':free():无效的下一个大小(快速):0x0000000001b27c20*
我知道这是在告诉我free()遇到一些没有分配给我的malloc()的内存,但这cout行在这里扮演什么角色?我想知道更多关于这里发生的事情。更具体地说,我有两个问题:
- 这是由这两种情况下堆的不同状态引起的吗?如果是,到底有什么不同
- 为什么有时访问超出范围的元素不会导致错误?是因为它还没有超过矢量的容量吗
行
cout << "test1n";
做了很多事情,它可能会分配一个空闲内存。
在向量的边界之外写入是"未定义的行为",这与"得到错误"非常不同。"未定义行为"的含义是,编写编译器和运行库的人可以自由忽略这些可能性,无论发生什么。他们之所以能做到这一点,是因为程序员永远不会做这些事情,而且什么时候做这些都是他/她的错。当使用operator[]
访问std::vector
元素时,防止、保护甚至简单地通知错误不是合同的一部分。
从技术上讲,可能发生的情况是写操作破坏了内存分配器使用的一些内部数据结构,这导致了之后的疯狂行为,这可能会也可能不会导致segfault。
segfault是指当事情变得疯狂到甚至操作系统都能检测到程序没有做应该做的事情,因为它请求访问甚至不存在的位置(因此可以肯定的是,这些位置不可能是应该包含要查找的数据的正确位置)。
然而,您可以在不到达"segfault"点的情况下获得未定义的行为和损坏的数据,并且程序只会从错误的位置读取或写入不正确的数据,即使与正确的程序没有任何可观察到的差异。这实际上是大多数时候都会发生的事情(不幸的是)。
那么,当您使用未选中的opertor[]
读取或写入超出std::vector
大小的内容时,会发生什么呢?大多数时候什么都没有(显然)。然而,在那次错误之后,它可能会为所欲为,包括在代码正确的地方表现得疯狂,10亿条机器指令之后,而且只有在这会造成严重损害的情况下。只是不要那样做。
当用C++编程时,你根本不会犯任何错误。在其他更高级别的语言中,没有"运行时错误天使"可以保护您。