为什么在类作用域中定义变量的顺序不重要?

huangapple go评论88阅读模式
英文:

Why doesn't it matter in which order define variables in class scope?

问题

如果我们在任何函数中执行这两行代码,都会出现错误,这是合理的,因为变量 b 在初始化 a = b 之后才定义:

int a = b;
int b = 0;

但是当我们将这两行代码插入到类的作用域中时,为什么类不关心 b 的定义顺序呢?

class Foo
{
    int a = b;
    int b = 0;
};
英文:

If we execute such two lines in any function, we will get an error, and this is logical because the variable b is defined after the initialization a = b:

int a = b;
int b = 0;

But when we insert these two lines into the scope of a class, why doesn't the class care about in which order b is defined?

class Foo
{
    int a = b;
    int b = 0;
};

答案1

得分: 14

类中声明成员的顺序确实很重要。

这个顺序决定了它们的初始化顺序。使用类似你示例中的默认初始化程序大致相当于使用具有成员初始化程序列表的构造函数:

class Foo
{
    int a;
    int b;
    Foo() : a(b), b(0) {}   // !! 未定义 !!
};

在这里,仍然初始化的顺序由成员声明的顺序决定,而不是它们在成员初始化列表中的顺序。编译器通常会在顺序不同的情况下发出警告。然而,在上面的示例中,问题变得更加明显:在初始化 b 之前使用 a 初始化 a 是未定义行为。

要正确地将一个成员的值初始化为另一个成员的值,必须遵守顺序:

class Foo
{
    int b = 0;  // 首先初始化
    int a = b;  // 正确
};
英文:

It does matter in which order you declare the members in a class.

The order determines in which order they are initialized. Using the default initializers like in your example is roughly equivalent to using this constructor with member initializer list:

class Foo
{
    int a;
    int b;
    Foo() : a(b) , b(0) {}   // !! undefined !!
};

Here, still the order of initializion is determined by the order the members are declared, not by their order in the member initializer list. Compilers usually warn when the order is different. Though, in the above the problem gets more obvious: a is initialized with b before b is initialized. Reading from b before its initialization is undefined behavior.

To correctly iniitalize one member with the value of another you must respect the order:

class Foo
{
    int b = 0;  // initialized first
    int a = b;  // OK
};

答案2

得分: 13

当你定义这两个非成员变量时,它们会立即初始化。

当你定义这两个成员变量时,初始化将在对象构造时发生,而不是在变量定义时发生。

然而,初始化是按照声明顺序进行的,因此a的初始化将使用未初始化和不确定b值,这将导致未定义行为

英文:

When you define the two non-member variables, they will be initialized immediately.

When you define the two member variables, the initialization will happen when the object is constructed, not when the variables are defined.

However initialization is made in declaration order, so the initialization of a will use the uninitialized and indeterminate value of b which leads to undefined behavior.

答案3

得分: 7

我想要添加一个观点:

未限定名称查找中,"成员函数定义"部分说:

对于在成员函数体内使用的名称,成员函数的默认参数,成员函数的异常规范,或默认成员初始化器,搜索的范围与类定义中的相同,只是考虑整个类的范围,而不仅仅是在使用名称的声明之前的部分。

因此,您甚至可以在类中的声明之前在这里使用 b


更新:正如其他答案所说,a 是用 b 初始化的,但在 b 初始化之前。请参见 https://godbolt.org/z/MT86nd3Yr,您会发现 a 实际上包含了一个垃圾值。

英文:

I would like to add a point:

In unqualified name lookup, section "Member function definition" says:
> For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in class definition, except that the entire scope of the class is considered, not just the part prior to the declaration that uses the name.

So you can even use b here before it is declared in classes.


Update: Just as the other answers say, a is initialized with b, but before b is initialized. See https://godbolt.org/z/MT86nd3Yr and you can find that a actually holds a trash value.

huangapple
  • 本文由 发表于 2023年6月8日 15:41:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429629.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定