成员初始化器列表和非静态数据成员的默认成员初始化器有什么区别?

我想了解使用一种形式而不是另一种形式(如果有的话)的区别.

I'd like to understand what's the differences of using one form rather than the other (if any).

代码1(直接在变量上初始化):

Code 1 (init directly on variables):

#include <iostream>

using namespace std;

class Test 
{
public:
    Test() {
        cout<< count;
    }

    ~Test();

private:
    int count=10;
};

int main()
{
    Test* test = new Test();
}

代码 2(在构造函数上初始化列表):

Code 2 (init with initialization list on constructor):

#include <iostream>

using namespace std;

class Test 
{
public:
    Test() : count(10) {
        cout<< count;
    }

    ~Test();

private:
    int count;
};

int main()
{
    Test* test = new Test();
}

语义上有什么区别,还是只是句法上的区别?

Is there any difference in the semantics, or it is just syntactic?

推荐答案

成员初始化

在这两种情况下,我们都在讨论成员初始化.请记住,成员在 在类中声明它们的顺序.

在第二个版本中:

Test() : count(10) {

: count(10) 是构造函数初始化器 (ctor-initializer) 和 count(10) 是一个 member initializer 作为成员初始化器列表的一部分.我喜欢将此视为初始化发生的真实"或主要方式,但它并不能确定初始化的顺序.

: count(10) is a constructor initializer (ctor-initializer) and count(10) is a member initializer as part of the member initializer list. I like to think of this as the 'real' or primary way that the initialization happens, but it does not determine the sequence of initialization.

在第一个版本中:

private:
    int count=10;

count 有一个默认成员初始化器.这是后备选项.如果构造函数中不存在,它将用作成员初始化器,但在类中确定了用于初始化的成员序列.

count has a default member intitializer. It is the fallback option. It will be used as a member initializer if none is present in the constructor, but in the class the sequence of members for initialization is determined.

来自标准的 12.6.2 初始化基和成员,第 10 项:

如果给定的非静态数据成员同时具有大括号或相等初始化器和一个内存初始化器,初始化执行由 mem-initializer 指定的非静态数据成员的大括号或相等初始化器被忽略.[示例:给定

If a given non-static data member has both a brace-or-equal-initializer and a mem-initializer, the initialization specified by the mem-initializer is performed, and the non-static data member’s brace-or-equal-initializer is ignored. [ Example: Given

struct A {
int i = / some integer expression with side effects / ;
A(int arg) : i(arg) { }
// ...
};

A(int) 构造函数将简单地将 i 初始化为 arg 的值,并且 i 的大括号或均衡器中的副作用不会出现地方.――结束示例]

the A(int) constructor will simply initialize i to the value of arg, and the side effects in i’s brace-or-equalinitializer will not take place. ―end example ]

要记住的其他一点是,如果你引入了一个非静态数据成员初始化器,那么在 C++11 中结构将不再被视为聚合,但这是 针对 C++14 更新.

Something else to keep in mind would be that if you introduce a non-static data member initializer then a struct will no longer be considered an aggregate in C++11, but this has been updated for C++14.

使用一种形式而不是另一种形式有什么区别(如果任何).

what's the differences of using one form rather than the other (if any).

  • 区别在于两个选项的优先级.直接指定的构造函数初始值设定项具有优先权.在这两种情况下,我们最终都会通过不同的路径得到一个成员初始化器.
  • 最好使用默认的成员初始化器,因为
    • 然后编译器可以使用该信息为您生成构造函数的初始化器列表,并且它可能能够进行优化.
    • 您可以在一处按顺序查看所有默认设置.
    • 它减少了重复.然后,您只能将异常放入手动指定的成员初始化器列表中.

相关文章