C++构造函数中初始化类成员并同步传递给基类的方案问询
C++ 初始化列表传递成员给基类构造的合法性说明
结论
你当前的写法属于未定义行为,不可以直接使用。
原因
C++ 类的初始化顺序严格遵循两条固定规则,不受初始化列表书写顺序影响:
- 派生类构造时,所有基类子对象的初始化永远早于派生类自身的非静态成员变量初始化
- 同层级的初始化顺序仅和声明顺序保持一致
你提供的代码中,MyClass的构造流程实际执行顺序是:
- 调用基类MyBase的构造函数,此时成员
m_Helper还未执行构造,属于生命周期尚未开始的对象 - 执行
m_Helper的构造函数
此时你给MyBase传入未初始化的m_Helper,哪怕仅做引用绑定不会立刻崩溃,但只要MyBase构造阶段访问了HelperBase的成员、调用虚函数,或是在m_Helper构造完成前使用了MyBase中存储的该引用,都会触发未定义行为,主流编译器也会针对该场景抛出警告。
可行解决方案
可以通过新增辅助持有类调整初始化顺序,保证Helper实例在传给MyBase前已经完成构造:
// 新增辅助基类,用于提前初始化Helper实例 struct HelperHolder { Helper m_Helper; explicit HelperHolder(MyClass& self) : m_Helper(self) {} }; // MyClass 先继承HelperHolder,再继承MyBase,保证初始化顺序符合预期 class MyClass : private HelperHolder, public MyBase { public: MyClass(); }; // 构造函数按继承顺序初始化即可 MyClass::MyClass() : HelperHolder(*this), MyBase(m_Helper) // 此时m_Helper已经被HelperHolder完成初始化,完全合法 {}
注意事项
- 上述方案中,Helper构造执行时MyBase还未完成初始化,因此不要在Helper的构造函数中访问MyBase的任何成员,否则仍会触发未定义行为
- 如果你的MyBase构造函数仅存储HelperBase的引用、完全不会在构造阶段访问该引用的内容,理论上原有写法可以勉强运行,但属于极度危险的不良实践,可维护性极差,稍有改动就会触发崩溃。
内容的提问来源于stack exchange,提问作者Robin Holenweger
相关产品推荐
相关产品推荐

