我有以下Stack类。
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输出也无济于事。
答案 0 :(得分:4)
编译器会自动将其重写为吗?
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] < / sup>发生,表示未初始化。然后,在x
的初始化中为其分配一个值。这是“安全的”,表示可以在这种情况下使用,但我不建议这样做。
Stack(const Stack& s) : size(s.size), x(new int[s.size]) {}
初始化两个成员,并且如果您在类中更改了它们的顺序,您仍将具有正确的行为。
答案 1 :(得分:2)
一个类的成员总是按照声明的顺序进行初始化,而不管您在成员初始化列表中指定的顺序如何。如果您省略它们,它们将被默认初始化。这样做:
Stack(const Stack& s) : x(new int[size=s.size]) {}
意味着size
首先被默认初始化。这给它留下了不确定的值(因为基本类型应该默认初始化)。然后评估x
的初始化程序。评估new int[size=s.size]
的一部分涉及赋值表达式size=s.size
,该表达式将size
修改为副作用。因此,尽管可能引起您的注意,但您的代码在这里是正确的。
在切换成员顺序时,分配发生在之前 size
应该被初始化。这会使您的代码容易受到未定义行为的影响。
答案 2 :(得分:0)
在constructors的Cppreference.com页面上:
出现在expression-list或brace-init-list中的名称在构造函数的范围内评估:
是的,这里的size
是指构造函数范围内的this->size
,赋值size=s.size
是有效的表达式。
不用说,您不应该期望它通过代码审查:)
答案 3 :(得分:0)
否,它将其重写为:
input
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
仍未初始化。 还是它?
我会说这段代码可能会产生未定义的行为。成员变量按照10.9.2 Initializing bases and members的声明顺序进行初始化。但是未定义用于初始化的表达式的求值顺序。因此,可以在 size
之前或之后调用size=s.size
。对于类类型,这将是一个问题,但是我不确定size()
是否保证为无操作,以及编译器是否可能决定将变量初始化为例如。 0。