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是数组类型,则数组的每个元素都是 默认初始化
    • 否则,什么也不做:具有自动存储持续时间的对象(及其子对象)被初始化为不确定值
    在我的示例中,构造函数初始值设定项列表中没有提到非静态数据成员,它是POD类型的数组。我希望不管我的结构是如何构造的,它都有不确定的值

    我的问题是:

    • 为什么编译器违反了这一点?我的意思是,为什么他们在不需要的时候放零,浪费我的运行时间?我读错了吗
    • 我如何强制执行这种行为以确保不浪费运行时用零填充数组
    • 为什么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