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?
我想知道在 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?