成员初始化列表中的赋值操作

Assignment operation in member initializer lists

我有以下堆栈 class。

class Stack{
public:
    int size;
    int* x;
    Stack() : size(10), x(new int[10]) {}
    Stack(const Stack& s) : x(new int[size=s.size]) {}

};

注意复制构造函数中的赋值。代码工作正常,编译器(gcc)即使使用 -Wall -Wextra 标志也不会抱怨。编译器会自动将编译器改写成这样吗?

Stack(const Stack& s) : size(s.size), x(new int[size]) {}

还是有其他魔法?我注意到,当我更改定义顺序时,编译器会抱怨未按顺序初始化。所以我假设这就是我提到的情况。我在文档中找不到任何内容,ASM 输出也没有帮助我。

来自 constructors 上的 Cppreference.com 页面:

Names that appear in expression-list or brace-init-list are evaluated in scope of the constructor:

所以是的,这里的size在构造函数的范围内引用了this->size,赋值size=s.size是一个有效的表达式。

不用说,您不应该期望它通过代码审查:)

class 的成员始终按声明顺序初始化,无论您在成员初始化列表中指定它们的顺序如何。如果您省略它们,它们将被默认初始化。所以这样做:

Stack(const Stack& s) : x(new int[size=s.size]) {}

表示默认先初始化size。这给它留下了一个不确定的值(因为基本类型应该是默认初始化的)。然后评估 x 的初始值设定项。评估 new int[size=s.size] 的一部分涉及赋值表达式 size=s.size,它修改 size 作为副作用。所以你的代码在这里是正确的,尽管可能会引起注意。

当您调换成员的顺序时,分配发生在之前 size 应该被初始化。这会使您的代码代码对未定义的行为开放。

Does the compiler automatically rewrite the compiler to this?

Stack(const Stack& s) : size(s.size), x(new int[size]) {}

没有

Stack(const Stack& s) : x(new int[size=s.size]) {}

可以认为是

Stack(const Stack& s) : size(), x(new int[size=s.size]) {}

但实际上并不是这样,因为实际上写 size() 会对其进行值初始化,这意味着它是零初始化的,但是由于它是综合初始化的编译器,因此默认初始化 [1] 发生意味着它没有被初始化。然后你在x的初始化中给它赋值。这是“安全的”,意味着它在这种情况下有效,但我不推荐它。

Stack(const Stack& s) : size(s.size), x(new int[s.size]) {}

初始化两个成员,如果您在 class 中更改它们的顺序,您仍然会有正确的行为。

不,它重写为:

class Stack{
public:
    int size;
    int* x;
    Stack() : size(10), x(new int[10]) {}
    Stack(const Stack& s) :size(), x(new int[size=s.size]) {}
};

size() 将是对象 size 的默认构造函数,但 int 没有,因此它只是一个空语句并且 size 保持未初始化. 或者是吗?

我会说这段代码可能会产生未定义的行为。成员变量按照 10.9.2 Initializing bases and members 声明的顺序进行初始化。但是用于初始化的表达式的求值顺序没有定义。因此,size=s.size 可以在 size() 之前或之后调用。对于 class 类型,这将是一个问题,但我不确定 size() 是否保证是无操作的,以及编译器是否可能决定将变量初始化为例如0.