所以,让我们说我正在使用这个玩具示例:
struct Foo {
int member;
};
我知道默认构造函数不会默认初始化member
。因此,如果我执行此操作,member
仍然未初始化:const Foo implicit_construction
。 除此之外,这似乎工作得很好:const Foo value_initialization = Foo()
虽然我的理解是这实际上并没有使用默认的构造函数。
如果我像这样更改Foo
:
struct Foo {
Foo() = default;
int member;
};
我尝试const Foo defaulted_construction
,毫不奇怪,它的行为与implicit_construction
完全相同,member
未初始化。
最后,如果我将Foo
更改为:
struct Foo {
Foo(){};
int member;
};
我这样做:const Foo defined_construction
member
零初始化。我只想弄清楚隐式定义的构造函数是什么样的。虽然我会Foo(){}
,但我会这样做。这不是这种情况吗?还有其他一些黑魔法可以使我定义的构造函数与默认构造函数的行为不同吗?
修改
也许我在这里误导了。 defaulted_construction
is definitely uninitialized。
While defined_construction
is definitely initialized
我认为这是标准化的行为,那是不正确的?
答案 0 :(得分:3)
您遇到的问题称为default initialization,其规则是(强调我的):
- 如果T是非POD(直到C ++ 11)类类型,则考虑构造函数并对空参数列表进行重载解析。选择的构造函数(它是默认构造函数之一)被调用以提供新对象的初始值;
- 如果T是数组类型,则数组的每个元素都是默认初始化的;
- 否则,什么都不做:具有自动存储持续时间的对象(及其子对象)被初始化为不确定值。
编辑,以回应OP的请求:
请注意declaring a constructor = default
不会改变情况(再次强调我的情况):
隐式定义的默认构造函数
如果隐式声明的默认构造函数未定义为已删除,则编译器会定义(即,函数体生成并编译),如果使用了odr,它与用户具有完全相同的效果 - 使用空体和空初始化列表定义构造函数。也就是说,它调用base的默认构造函数和此类的非静态成员。
由于默认构造函数具有空的初始化列表,因此其成员满足conditions for default initialization:
默认初始化在以下三种情况下执行:
...
3)在构造函数初始值设定项列表中未提及基类或非静态数据成员且调用该构造函数时。
另请注意,在通过实验确认时必须小心,因为int
的默认初始化值可能完全可能为零。特别是,你提到了这个:
struct Foo {
Foo(){};
int member;
} foo;
value-initialization中的结果,但没有;在这里,member
是默认初始化的。
编辑2:
请注意以下区别:
struct Foo {
int member;
};
Foo a; // is not value-initialized; value of `member` is undefined
Foo b = Foo(); // IS value-initialized; value of `member` is 0
遵循value-initialization的规则:
可以理解此行为在以下情况下执行值初始化:
1,5)当使用由一对空括号组成的初始化程序创建无名临时对象时;
表单1(T();
)是上方=
右侧用于初始化b
的表单。
值初始化的影响是:
1)如果T是没有默认构造函数的类类型,或者是用户提供或删除的默认构造函数,则该对象是默认初始化的;
2)如果T是具有默认构造函数的类类型,该构造函数既不是用户提供也不是删除(也就是说,它可能是具有隐式定义或默认默认构造函数的类),该对象是零初始化的并且如果它有一个非平凡的默认构造函数,则默认初始化;
3)如果T是数组类型,则数组的每个元素都是值初始化的;
4)否则,该对象为零初始化。
最后请注意,在我们之前的例子中:
struct Foo {
Foo(){}; // this satisfies condition (1) above
int member;
};
Foo f = Foo();
现在,条件(1)适用,而我们的(空)用户声明的构造函数被调用。由于此构造函数未初始化member
,因此member
默认初始化(因此其初始值未定义)。