You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

取未初始化对象成员的地址是否为定义良好行为?附代码实例问询

问题分析:未定义行为的根源

这个问题的答案很明确:这段代码的行为是未定义的,不属于合法且定义良好的行为。下面来拆解原因和问题所在:

1. C++构造初始化的固定顺序

首先要明确C++中派生类对象的构造流程:

  • 当构造bar对象时,会先调用基类foo的构造函数,完成基类的初始化;
  • 之后才会初始化bar的非静态成员my_member。

这个顺序是由C++标准强制规定的,和你在初始化列表中写的顺序(foo(&my_member.y), my_member(42))完全无关——哪怕你把my_member的初始化写在前面,基类构造依然会先执行。

2. 核心问题:引用未构造对象的成员

在bar的构造初始化列表中,我们向foo的构造函数传入了&my_member.y,但此时my_member这个member类型的对象还没有开始构造(它的构造函数要等foo构造完成后才会运行)。

根据C++标准的[class.cdtor]/1条款:

对于拥有非平凡构造函数的对象,在其构造函数开始执行之前,引用该对象的任何非静态成员或基类,都会导致未定义行为。

这里的member类拥有用户自定义的构造函数(属于非平凡构造函数),所以在它的构造函数执行前,取&my_member.y(本质是引用它的成员y)的操作已经触发了未定义行为。

3. 未定义行为的影响

哪怕后续my_member被正确初始化为42,main中解引用地址时看起来能输出预期值,但未定义行为意味着程序的行为完全不受标准保障——编译器可以任意优化这段代码、输出随机值、甚至导致程序崩溃,一切结果都是不可预测的。

如何修正?

要避免这种问题,必须确保在引用成员对象的任何部分之前,该成员对象已经完成初始化。常见的修正方案有两种:

方案1:基类提供后续设置指针的接口

修改foo类,增加默认构造函数和指针设置方法,在my_member初始化完成后再赋值:

struct foo { 
    foo() : x(nullptr) {} // 默认构造函数
    void set_x(int* p_x) { x = p_x; }
    int* x; 
};

struct bar : foo { 
    bar() : my_member(42) {
        set_x(&my_member.y); // 此时my_member已经构造完成,引用成员是安全的
    }
    member my_member;
};

方案2:调整类结构(如果允许)

如果业务逻辑允许,可以把my_member改为bar的基类(基类初始化顺序是按继承声明顺序来的),这样my_member会先于foo初始化:

struct bar : member, foo { 
    bar() : member(42), foo(&y) {} // 此时member已经初始化,&y是安全的
};

内容的提问来源于stack exchange,提问作者François Andrieux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:34:30