在基类构造函数调用前初始化其POD成员是否符合C++标准?
关于派生类构造函数中提前修改基类成员的合法性分析
问题场景代码
class Base { protected: int v; Base( void * ) { /* doesn't touch v at any point */ } }; class Derived: public Base { public: // Changes Base::v before calling Base::Base Derived(): Base( ( (void )( v = 42 ), nullptr ) ) {} };
场景说明:Derived的构造函数试图在调用Base构造函数之前,通过逗号表达式修改基类的POD成员v,且Base的构造函数完全不操作v,目标是让v最终被初始化为42。需要判断该行为是否合法,是否属于会被编译器优化的未定义行为。
结论:该行为属于未定义行为
标准条款依据
基类子对象的生命周期起点
根据C++标准[basic.life]章节的定义,类对象(包括作为派生类一部分的基类子对象)的生命周期从其构造函数的执行开始时启动。在Derived构造函数的初始化列表中,Base构造函数的调用是Base子对象生命周期的起始点——在此之前,Base子对象的内存虽然已分配,但并未成为一个具有合法生命周期的对象。访问未激活对象成员的限制
[basic.life]/6规定:对于尚未开始生命周期的对象,仅允许对其底层内存进行无类型的操作(例如通过std::byte指针读取/写入内存),直接访问其非静态数据成员属于未定义行为,即便该成员是POD类型也不例外。
代码中的v = 42是直接访问了尚未进入生命周期的Base子对象的成员v,完全违反了上述规则,属于明确的未定义行为。
- 编译器优化的不确定性
因为该行为属于未定义行为,编译器可以对这段代码进行任意优化:比如直接忽略v = 42的赋值,或者产生与预期不符的内存操作结果。即使当前某款编译器的输出符合预期,这也只是特定实现下的巧合,并不符合C++标准的要求,更换编译器、版本或优化等级都可能导致行为异常。
内容的提问来源于stack exchange,提问作者dragonroot
相关产品推荐
相关产品推荐

