构造函数如何创建和初始化成员变量?

问题描述

考虑以下具有成员初始值设定项列表的类:

class A {
public:
    A() : a {b} {
       // do something
    }
private:
    int a {1};
    int b {2};
};

编译器发出警告,指出在成员初始化器列表中使用了未初始化的 b。这是否意味着成员 b 已经创建但尚未初始化?

因此,我们可以假设以下执行顺序吗?

  1. 调用构造函数 A()
  2. int a; (为a创建内存)
  3. int b; (为 b 创建内存)
  4. a = b; (编译器警告)
  5. b = 2; (将认值 2 分配给 b)
  6. 执行构造函数

这意味着,我们实际上并不初始化而是在步骤 4 和 5 中赋值?

编辑: 如果是这样,当在进入块之前创建成员之后也可以在块中进行赋值时,初始化列表的优势是什么?

解决方法

您描述的顺序不完全正确。顺序基本如下:

  1. 为对象分配了内存; (例如使用 operator new)请注意,内存不是单独分配的。对象的内存是连续的,可能在 ab 之间有填充。
  2. 成员的初始化是在构造函数的初始化列表中或直接在成员声明中提供初始化器的地方完成的。在这种情况下,先声明 a,然后声明 b,这就是为什么在您尝试读取它以初始化 b 时尚未初始化 a
  3. 执行构造函数体。

请注意,字段是初始化的,未分配的,这在 int 的情况下没有区别,但如果成员类型提供赋值运算符和构造函数,则两者之间会有所不同;如果在声明时使用初始化列表或初始化成员变量,则始终使用构造函数。