C++中含用户提供构造函数基类的类类型变量零初始化问题
问题解答
前置事实确认
你对struct B的构造函数属性判断完全正确:
- B没有用户声明的默认构造函数,编译器会隐式生成默认构造函数
- 该默认构造函数是非平凡的:因为需要调用基类A的自定义构造函数
- 该默认构造函数不属于「用户提供」的范畴:你没有手动在B的定义中编写该构造函数
b1初始化行为分析
B b1 = B();中B()触发值初始化,最终行为由你使用的C++标准版本决定:
C++03规则
值初始化时,只要类拥有非平凡默认构造函数,就直接调用默认构造函数,不会提前做零初始化:
- 调用B的隐式默认构造函数,会先调用A的构造函数,将x、y初始化为0
- B的隐式构造函数不会初始化int类型成员z,因此z是未定义的不确定值
- 最终b1没有完成全对象零初始化
C++11及更新版本规则
值初始化规则被修改:如果类没有用户提供的默认构造函数,会先对整个对象做零初始化,再调用默认构造函数:
- 零初始化阶段:整个b1对象的内存被清零,x、y、z都被设为0
- 调用B的隐式默认构造函数:再次调用A的构造函数将x、y设为0,不会修改z的值
- 最终b1的所有成员都是0,完成零初始化
b2初始化行为分析
B b2{};的行为同样和C++标准相关:
C11 ~ C14规则
有基类的类不属于聚合类型,因此B{}触发值初始化,行为和B()完全一致:C11/14下b2全零初始化,C03下z为不确定值。
C++17及更新版本规则
C++17允许拥有公开非虚基类的类成为聚合类型,因此B{}触发聚合初始化:
- 空初始化列表会对所有未显式指定初始化器的成员/基类执行零初始化
- 基类A被零初始化后调用构造函数,x、y为0;成员z直接被零初始化
- 无论任何情况,b2的所有成员都是0,完成零初始化
实际开发表现
当前主流编译器(GCC、Clang、MSVC)默认使用C17及以上标准,因此实际开发中你看到的b1、b2都会是全零状态。如果手动指定C03标准编译,b1的z会是未初始化的随机值。
内容的提问来源于stack exchange,提问作者Markus
相关产品推荐
相关产品推荐

