为什么未初始化容器的行为与优化不同

Why is the behavior of uninitialized containers different with optimizations?

本文关键字:优化 初始化 为什么      更新时间:2023-10-16

Given是一个具有以下元素的类:

std::array<Class*, 4> children;

在调试模式下,检查nullptr上未初始化数组的元素会返回true

if(children[0]==nullptr)

然而,在发布模式下(启用了优化,无论O1、O3还是Os),检查返回false

元素似乎是以某种方式初始化的,但访问它们仍然会导致分割错误。为了避免这种行为,我必须用nullptr元素显式初始化std::array

std::array<Class*, 4> children{{nullptr}};

为什么会出现这种情况?

编辑:在这种情况下使用的编译器是Apple LLVM 4.2 (Xcode 4.6.3)

std::array与内置数组一样,是一个聚合,因此如果元素不是用户定义的类型(默认构造用户定义类型的元素),则不能保证自动初始化。不能依赖于具有任何特定值的元素。在您的情况下,可能是在调试(非优化)模式下,它从堆栈中分配碰巧已经清零的新空间,但启用了优化后,编译器可能会意识到它可以重用不再需要的空间,但保留旧数据。

在调试模式下,行为取决于编译器。有些编译器/调试器设置了魔术值(例如VS使用0xCDCDCD),有些则使用零(一点也不好)。在释放模式下,内存未初始化。这就是为什么它可以用一些编译器以调试方式工作,但永远不会在发布版中工作。

因为未初始化的(不是静态存储持续时间的)变量的内容是"不确定的"-不可能知道它会是什么,并且可能因各种因素而异。

编译器将为不同的优化级别生成不同的代码,这可能会导致内存中变量的布局不同。如果你想看到可预测的行为,那么你必须初始化变量。其他任何事情,都将取决于许多因素,包括优化级别,你得到的"结果"。

Visual可以在未初始化的内存上设置幻数无论如何都不能明显地测试未初始化的内存