structs/classes 在堆栈与堆中没有构造函数的初始化

initialization of structs/classes without constructors in stack vs heap

我想知道在 C++ 中将没有默认构造函数的结构(或 类)清零的规则。

特别是,如果存储在堆栈中(例如,作为局部变量),它们似乎是未初始化的,但如果分配在堆上,它们是零初始化的(使用 GCC 4.9.1 测试)。 这能保证便携吗

示例程序:

#include <iostream>
#include <map>
using namespace std;

struct X {
    int i, j, k;
    void show() { cout << i << " " << j << " " << k << endl; }
};

int fib(int i) {
    return (i > 1) ? fib(i-1) + fib(i-2) : 1;
}

int main() {
    map<int, X> m;            
    fib(10);                  // fills the stack with cruft
    X x1;                     // local
    X &x2 = m[1];             // heap-allocated within map
    X *x3 = new X();          // explicitly heap-allocated
    x1.show();  // --> outputs whatever was on the heap in those positions
    x2.show();  // --> outputs 0 0 0 
    x3->show(); // --> outputs 0 0 0     
    return 0;
}

已编辑:删除粗体部分的 "or should I just use a constructor";因为让我问的是我想知道它是否是有保证的行为 - 我们都同意可读代码比显式构造函数更好。

如果您想为 class 的成员提供特定值,请始终使用构造函数。这就是构造函数的真正用途。唯一不需要编写构造函数来设置所需值的情况是,如果语言预先为您提供了一个构造函数,例如复制构造函数。 int 和其他此类类型的默认构造函数不在此列表中,因此您必须将构造函数添加到您自己的类型以适当地设置它们。

零初始化您的 struct 成员的不是动态分配;这是你的语法:

X* ptr = new X();
//            ^^
// 
// as opposed to just:
X* ptr = new X;

如果你想保证它,就继续写吧。 :)

与自动存储持续时间等效的替代方法是使用更新的 {} 语法:

X* ptr = new X{};   // dynamic
X  obj{};           // automatic

无论如何,具有静态存储持续时间的对象总是预零初始化,所以默认情况下你会被覆盖。

只要您没有任何构造函数,所有成员都是 public,并且不涉及继承,您的 struct/class 很可能是一个聚合。

要获得可移植的零初始化,只需使用执行零初始化的 X x = {};

这是关于聚合 (8.5.1) 的标准引用:

An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no brace-or-equal-initializers for non-static data members (9.2), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).

参考:Why can I not brace initialize a struct derived from another struct?