成员初始化列表中的赋值操作
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.
我有以下堆栈 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.