如果所有对象都至少有一个构造函数,则默认情况下由编译器或用户定义,然后如何对象未初始化。
答案 0 :(得分:15)
可以声明执行无初始化的对象。这些对象确实存在,它们具有不确定值,并且使用此值是未定义的行为(此规则对于字符有例外)。
此类对象可以通过 default-intialization 创建。 这在c ++标准中有说明,(第11.6节初始化器)[dlc.init]:
要默认初始化 T类型的对象意味着:
(7.1) - 如果T是(可能是cv限定的)类类型(第12条),则考虑构造函数。适用 枚举构造函数(16.3.1.3),通过重载选择初始化程序()的最佳构造函数 决议(16.3)。这样选择的构造函数用空参数列表调用,以初始化 对象
(7.2) - 如果T是数组类型,则每个元素都是默认初始化的。
(7.3) - 否则,不进行初始化。
尽管如此,静态对象总是零初始化。因此,任何具有动态或自动存储持续时间的内置函数都可能无法初始化,即使它是一个子对象;
int i; //zero-initialized
struct A{
int i;
};
struct B
{
B(){};
B(int i)
:i{i}{}
int i;
int j;
};
A a; //a.i is zero-initialized
int main()
{
int j; //not initialized
int k{}; //zero-initialized
A b; //b.i not initialized
int* p = new int; //*p not initialized
A* q = new A; //q->i not initialized
B ab; //ab.i and ab.j not initialized
B ab2{1}; //ab.j not initialized
int xx[10]; //xx's element not initialized.
int l = i; //OK l==0;
int m = j; //undefined behavior (because j is not initialized)
int n = b.i; //undefined behavior
int o = *p; //undefined behavior
int w = q->i; //undefined behavior
int ex = x[0] //undefined behavior
}
对于成员初始化[class.base.init]可能会有所帮助:
在非委托构造函数中,如果给定的可能构造的子对象未由mem-指定 initializer-id(包括没有mem-initializer-list的情况,因为构造函数没有 ctor-initializer),然后 - 如果实体是具有默认成员初始值设定项(12.2)和
的非静态数据成员(9.1.1) - 构造函数的类是一个联合(12.3),并且没有指定该联合的其他变体成员 通过mem-initializer-id或
(9.1.2) - 构造函数的类不是联合,并且,如果实体是匿名联合的成员,则不 该联盟的其他成员由mem-initializer-id指定, 实体从其默认成员初始值设定项初始化,如11.6;
中所述(9.2) - 否则,如果实体是匿名联合或变体成员(12.3.1),则不进行初始化 执行;
(9.3) - 否则,实体默认初始化(11.6)
一个简单的匿名联盟的成员也可能没有被初始化。
也可以询问是否可以在没有任何初始化的情况下开始对象生命周期,例如使用reinterpret_cast。答案是否:reinterpret_cast creating a trivially default-constructible object
答案 1 :(得分:1)
标准没有讨论对象的存在,但是,有一个生命周期对象的概念。
具体来说,来自[basic.life] †
类型为
T
的对象的生命周期始于:
获取具有
T
类型的正确对齐和大小的存储,如果对象具有非空的初始化,则其初始化完成
将非空初始化定义为
如果一个对象属于一个类或aggregate type,并且它或其一个子对象是由trivial default constructor以外的构造函数初始化的,则称该对象具有非空的初始化。
我们可以得出结论,对于具有空初始化的对象(例如int
s),他们的生命周期在获取存储后立即开始,即使它们未被初始化。
void foo()
{
int i; // i's lifetime begins after this line, but i is uninitialized
// ...
}
†为了便于阅读而添加链接,它们没有出现在标准中