成员初始化程序列表和非静态数据成员上的默认成员初始值设定项之间的区别是什么?

mar*_*zzz 12 c++ variables class init

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

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

#include <iostream>

using namespace std;

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

    ~Test();

private:
    int count=10;
};

int main()
{
    Test* test = new Test();
}
Run Code Online (Sandbox Code Playgroud)

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

#include <iostream>

using namespace std;

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

    ~Test();

private:
    int count;
};

int main()
{
    Test* test = new Test();
}
Run Code Online (Sandbox Code Playgroud)

语义有什么不同,或者它只是语法吗?

Kat*_*ory 9

在C++核心指南中(参见下面的注释1),指南C.48推荐了第一种方法(类内初始化器).提供的推理是:

明确表示在所有构造函数中使用相同的值.避免重复.避免维护问题.它导致最短和最有效的代码.

事实上,如果您的构造函数除了初始化成员变量之外什么也没做,就像在您的问题中那样,那么Guideline C.45仍然更加坚定,他说要使用类内初始化器.它解释了这一点

使用类内成员初始值设定项可让编译器为您生成函数.编译器生成的函数可以更高效.

即使我没有编写编译器,我也不会与Stroustrup,Sutter和他们的几百个朋友和同事争论,因此我无法证明它更有效率.尽可能使用类内初始值设定项.

  1. 如果您不熟悉指南,请按照链接查看示例代码和更多说明.


wal*_*lly 8

成员初始化

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

代码2:成员初始化器列表

在第二个版本中:

Test() : count(10) {
Run Code Online (Sandbox Code Playgroud)

: count(10) 是一个构造函数初始化(构造函数初始化程序),并count(10)是一个成员初始化为初始化列表的构件的一部分。我喜欢将其视为初始化发生的“真实”或主要方式,但它不能确定初始化的顺序。

代码1:默认成员初始化器

在第一个版本中:

private:
    int count=10;
Run Code Online (Sandbox Code Playgroud)

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

从第12.6.2节“ 初始化基础和成员”中,本标准的第10项

如果给定的非静态数据成员同时具有大括号或相等初始化程序和mem初始化程序,则执行由mem初始化程序指定的初始化,并且非静态数据成员的大括号或相等初始化程序为忽略了。[示例:已知

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

A(int)构造函数将简单地将i初始化为arg的值,并且不会发生i的brace-or-equalinitializer的副作用。—结束示例]

还有一点要记住的是,如果您引入了非静态数据成员初始化程序,则在C ++ 11中不再将结构视为聚合,但是已针对C ++ 14更新了该结构。


差异性

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

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


son*_*yao 5

我能想到的差异是成员初始化列表默认成员初始化程序之前.

通过默认成员初始值设定项,它只是成员声明中包含的大括号或等于初始值设定项,如果在成员初始值设定项列表中省略该成员,则使用该初始值设定项.

如果成员具有默认成员初始值设定项并且也出现在构造函数的成员初始化列表中,则忽略默认成员初始值设定项.

例如:

class Test 
{
public:
    Test() {}  // count will be 10 since it's omitted in the member initializer list
    Test(int c) : count(c) {} // count's value will be c, the default member initializer is ignored. 
private:
    int count = 10;
};
Run Code Online (Sandbox Code Playgroud)