C++ 为什么编译器在不必将零放入数组的情况下将其放入数组?
我试图理解编译器什么时候应该初始化数组,什么时候应该默认初始化数组。我尝试两种选择:一种是原始数组,另一种是聚集在结构中的数组:C++ 为什么编译器在不必将零放入数组的情况下将其放入数组?,c++,arrays,initialization,C++,Arrays,Initialization,我试图理解编译器什么时候应该初始化数组,什么时候应该默认初始化数组。我尝试两种选择:一种是原始数组,另一种是聚集在结构中的数组: const int N = 1000; struct A { uint32_t arr[N]; A() = default; }; void print(uint32_t* arr, const std::string& message) { std::cout << message << ": "
const int N = 1000;
struct A
{
uint32_t arr[N];
A() = default;
};
void print(uint32_t* arr, const std::string& message)
{
std::cout << message << ": " <<
(std::count(arr, arr + N, 0) == N ? "all zeros" : "garbage") << std::endl;
}
int main()
{
uint32_t arrDefault[N];
print(arrDefault, "Automatic array, default initialization");
uint32_t arrValue[N] = {};
print(arrValue, "Automatic array, value initialization");
uint32_t* parrDefault = new uint32_t[N];
print(parrDefault, " Dynamic array, default initialization");
uint32_t* parrValue = new uint32_t[N]();
print(parrValue, " Dynamic array, value initialization");
A structDefault;
print(structDefault.arr, "Automatic struct, default initialization");
A structValue{};
print(structValue.arr, "Automatic struct, value initialization");
A* pstructDefault = new A;
print(pstructDefault->arr, " Dynamic struct, default initialization");
A* psstructValue = new A();
print(psstructValue->arr, " Dynamic struct, value initialization");
}
的输出仅在第一行中不同,在第一行中它还放置“全零”
在我看来,他们都错了,我所期望的是:
Automatic array, default initialization: garbage
Automatic array, value initialization: all zeros
Dynamic array, default initialization: garbage
Dynamic array, value initialization: all zeros
Automatic struct, default initialization: garbage
Automatic struct, value initialization: garbage
Dynamic struct, default initialization: garbage
Dynamic struct, value initialization: garbage
也就是说,对于原始数组(gcc除外),输出是正常的:默认值为垃圾,值为零。伟大的但对于一个结构,我希望一直都有垃圾。发件人:
默认初始化在三种情况下执行:
- 如果T是非POD(直到C++11)类类型
- 如果T是数组类型,则数组的每个元素都是 默认初始化李>
- 否则,什么也不做:具有自动存储持续时间的对象(及其子对象)被初始化为不确定值
- 为什么编译器违反了这一点?我的意思是,为什么他们在不需要的时候放零,浪费我的运行时间?我读错了吗
- 我如何强制执行这种行为以确保不浪费运行时用零填充数组
- 为什么gcc会对自动数组执行值初始化
结构值{}代码>是聚合初始化,因此保证为0
由于A
没有用户提供的构造函数,因为显式默认的构造函数不计算在内,这同样适用于A*psstructValue=new A()中的值初始化代码>
对于默认的初始化情况:读取未初始化的变量是UB,未定义的行为是未定义的。编译器可以做任何它想做的事情。向您显示0与崩溃一样合法。也许你偶然读到的记忆中甚至有0。可能编译器感觉像0正在初始化。从标准的角度来看,两者都同样好
也就是说,当使用发布/优化的构建进行测试时,您有更好的机会看到垃圾。调试构建倾向于做额外的事情来帮助诊断问题,包括做一些额外的初始化
(作为记录:gcc和clang with-O3乍一看似乎没有在我的Linux系统上进行不必要的初始化。然而,我在每种情况下都得到了“全零”。这似乎是偶然的。)另一个答案并没有真正说明原因,只是在某种程度上与语言规范有关
实际原因在于初始化过程的工作方式
问自己这样一个问题:我如何知道某个东西是否已初始化
这就是为什么静态数据需要初始化,而非静态数据则不需要初始化的原因。如果您没有首先检查并将所有静态数据归零,那么静态-动态初始化过程(查找)基本上是不可能的
您会经常遇到类似于两个静态的问题,它们在初始化时倾斜地相互引用,而所有内容都会崩溃
没有这个规则,C++基本上是不可能编写编译器的。尽管还有其他初始化方案不具备这一要求,但要实现它们,需要对语言进行大的修改。为什么编译器违反了什么?我在你的代码中没有发现任何违反标准的行为。另一方面,我可能错过了很多东西。如果值不确定,编译器不允许写零吗?@Theodoroschatzigannakis允许写零,但编译器试图生成非常优化的代码。为什么他们应该把零放进去,而他们却被允许不这样做?如果必须的话,唯一可能的原因是。值初始化意味着您得到零。零并不意味着你有值初始化。@juanchopanza我理解。但我可以清楚地看到零。为什么?很好地理解了聚合初始化。对于其余的,我不相信这些程序只是打印任何他们想要的由于UB。所有的案例都有UB,但有些有垃圾,有些没有。我相信这是因为他们诚实地查看了记忆中的正确位置。@Mikhail,正如我所说,UB是未定义的。不管怎样,编译器初始化都是完全正确的,因为您不能合法地观察到任何差异。那么您认为,编译器是否将零放在那里?我明白这是允许的,也明白我只能通过内存转储和解构来直接观察它,但是,你的说法是什么?@Mikhail我认为你为什么看到零并不重要。无论如何,你都不能依赖这两种行为。可能是编译器或操作系统空值的东西。做了一些性能测试。请看,你的答案是什么?
Automatic array, default initialization: garbage
Automatic array, value initialization: all zeros
Dynamic array, default initialization: garbage
Dynamic array, value initialization: all zeros
Automatic struct, default initialization: garbage
Automatic struct, value initialization: garbage
Dynamic struct, default initialization: garbage
Dynamic struct, value initialization: garbage