在初始评估列表中引用类成员是不确定的行为吗?

Is it undefined behavior to refer to class members in an initialiser list?

本文关键字:不确定 成员 评估 列表 引用      更新时间:2023-10-16

假设我有以下内容:

class A {
   B member1;
   C member2;
public:
   A();
};
class B {
public:
   C& ref_to_c;
   B( C& ref_to_c );
};
class C {
 ...
};

b要求在其构造函数上提供对C的引用。如果A类提供C,则指定A的初始列表列表是合法的...

A() : member1( B( member2 ) ) {}

也就是说,构件2是否存在于初始列表阶段,还是此不确定的行为

Intialization如下:

5初始化应按以下顺序进行:

- 首先,仅适用于最派生的类的构造函数 下面描述的是,虚拟基类应在 命令它们出现在深度最先进的左右遍历 基本类的定向无环图,其中"从左到右"是 派生类中基类名称的外观顺序 基本列表。

- 然后,直接基类应按声明顺序初始化 当它们出现在基本列表中时 mem-intializer)。

- 然后,非静态数据成员应按顺序初始化 他们在班级定义中被宣布(再次 mem-initializers的顺序)。

- 最后,执行构造函数的主体。[注意: 要求宣布令确保基础和成员 亚对象以初始化的相反顺序被破坏。]


基本上意味着member1将始终在member2之前初始化。因此,B的构造函数将首先运行。即使您在A的构造函数中以相反的顺序称呼它们:

A() : member2(foo), member1(bar) {}

it 不有所作为。现在,引用非初始化对象本身不是UB,但可以取决于B的构造函数。您应该切换声明的顺序:

C member2;
B member1;

您正在编造包含对memebr2的引用的member1。尚未构建,但是编译器已经知道它的位置(因此可以提供参考)。

它将起作用,但是如果您尝试的话,将是ub,例如,在b ctor-中 - 以某种表达式访问 ref_to_c值,因为该引用实际上是在使一个非初始化的内存混为一谈,这将在成员2构建过程中初始化,那将在以后发生。

在B Destructor中将存在同样的问题,在ref_to_c之前将销毁member2

如果您在a中交换成员2和member1会更好,这样您将用构造的对象初始化参考,从而使所有可能的用法(定义)。