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

时间:2019-03-07 13:28:34

标签: c++ constructor member-initialization

我有以下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输出也无济于事。

4 个答案:

答案 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。