C++ 默认构造函数是否总是初始化所有成员?
我发誓我不记得以前见过这个,我很难相信我的眼睛: 非聚合类的隐式定义的默认构造函数是否初始化其成员 在VisualC++中,当我运行这个无辜的代码…< /P>C++ 默认构造函数是否总是初始化所有成员?,c++,visual-c++,constructor,initialization,default-constructor,C++,Visual C++,Constructor,Initialization,Default Constructor,我发誓我不记得以前见过这个,我很难相信我的眼睛: 非聚合类的隐式定义的默认构造函数是否初始化其成员 在VisualC++中,当我运行这个无辜的代码…< /P> #include <string> struct S { int a; std::string b; }; int main() { return S().a; } #包括 结构S{inta;std::string b;}; int main(){return S().a;} 。。。令我惊讶的是,它返回了一个非零值!但如果
#include <string>
struct S { int a; std::string b; };
int main() { return S().a; }
#包括
结构S{inta;std::string b;};
int main(){return S().a;}
。。。令我惊讶的是,它返回了一个非零值!但如果我删除字段b
,那么它将返回零
我已经在我能接触到的所有版本的VC++上试过了,而且似乎在所有版本上都能做到这一点
但是,当我在Clang和GCC上尝试时,无论我是在C++98模式还是在C++11模式下尝试,值都初始化为零
正确的行为是什么?不保证为零吗?(第一节中的所有引用均来自N3337,C++11 FD,并进行了编辑性修改)
我不能用这种方法复制这种行为。大概这个bug(见下文)已经在他们使用的版本中修复了,但在您的@Drop报告中没有,最新版本VS 2013 Update 4没有通过断言,而VS 2015预览版通过了它们
为了避免误解:S
确实是一个集合。[dcl.init.aggr]/1:
聚合是没有提供用户的数组或类(第9条)
构造函数(12.1),没有私有或受保护的非静态数据成员
(第11条),没有基类(第10条),也没有虚函数
(10.3)
但这并不重要。值初始化的语义很重要。[dcl.init]/11: 初始值设定项为空括号集的对象,即。,
()
,应进行值初始化
[dcl.init]/8:
对T
类型的对象进行值初始化意味着:
- 如果
是(可能是cv限定的)类类型(第9条),没有默认构造函数(12.1)或 用户提供或删除的默认构造函数,则对象默认初始化李>T
- 如果
是一个(可能是cv限定的)类类型,没有用户提供或删除的默认构造函数,则对象为零初始化并检查默认初始化的语义约束,如果T
具有非平凡的默认构造函数,则对象为默认初始化对象李>T
- [……]
b
是否在S
中,这都是有效的。因此,至少在C++11中,在这两种情况下,a
都应该为零
现在让我们看看C++03 FD: 对
T
类型的对象进行值初始化意味着:
- 如果
是一个类类型(第9条),且具有用户声明的构造函数(12.1)[..]T
- 如果
是没有用户声明构造函数的非联合类类型,则每个非静态数据成员和基类T
的组件初始化为值强>T
- 如果
是数组类型,则每个元素都初始化了值李>T
- 否则,对象初始化为零
a
在这两种情况下都应该是0
。同样,使用-std=c++03 如中所示,您的版本与C++98兼容,并且仅与C++98兼容。引用C++11: 5.2.3显式类型转换(函数表示法)[expr.type.conv] 2表达式
T()
,其中T
是非数组完整对象类型或(可能是cv限定的)void
类型的简单类型说明符或类型名说明符,创建指定类型的PR值,该值已初始化(8.5;未对void()
案例进行初始化)。[……]
8.5初始值设定项[dcl.init]
7初始化类型为T
的对象的值意味着:
- 如果
是没有用户提供构造函数的(可能是cv限定的)非联合类类型,则对象初始化为零,如果T
隐式声明的默认构造函数是非平凡的,则调用该构造函数T
S().a
应该为零:在调用构造函数之前,对象初始化为零,构造函数从不将a
的值更改为任何其他值
在C++11之前,值初始化有不同的描述。引用N1577(大致为C++03):
初始化T类型对象的值意味着:
- 如果
是一个没有用户声明构造函数的非联合类类型,那么T
的每个非静态数据成员和基类组件都是初始化值李>T
- 否则,对象初始化为零
S
的值初始化没有调用任何构造函数,而是导致其a
和b
成员的值初始化。然后,该成员的值初始化导致该特定成员的零初始化。在C++03中,结果也保证为零
甚至早于此,我们来看看最早的标准C++98:
表达式T()
,其中T
是非数组完整对象类型或(可能是cv限定的)void
类型的简单类型说明符(7.1.5.2),创建指定类型的右值,其值由默认初始化确定(8.5;不对void()
案例进行初始化)
默认情况下,初始化类型为T
的对象意味着:
- 如果
T
是非POD类类型(第9条),则调用T
的默认构造函数(如果T
没有可访问的数据,则初始化是错误的)