C++ 在构造函数中初始化字段 - 初始化列表与构造函数主体

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9903248/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:23:11  来源:igfitidea点击:

Initializing fields in constructor - initializer list vs constructor body

c++parameters

提问by gardian06

I have been working in c++ for some time now, but I am unsure about the difference between

我已经在 c++ 中工作了一段时间,但我不确定两者之间的区别

public : Thing(int _foo, int _bar): member1(_foo), member2(_bar){}

and

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}

I have a feeling that they do the same thing, but is there a practical difference between these 2 syntaxes. Is one of these safer then the other, and do they handle default parameters differently.

我有一种感觉,他们做同样的事情,但这两种语法之间是否存在实际差异。其中之一是否比另一个更安全,并且它们是否以不同的方式处理默认参数。

Not totally accustomed to the first example so if I made a mistake on it I apologize.

不完全习惯第一个例子,所以如果我犯了错误,我道歉。

回答by Luchian Grigore

They are not the same if member1and member2are non-POD (i.e. non-Plain Old Data) types:

他们是不一样的,如果member1member2是非POD(即非PLAIN ØLD dATA)类型:

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}

is equivalent to

相当于

public : Thing(int _foo, int _bar) : member1(), member2(){
    member1 = _foo;
    member2 = _bar;
}

because they will be initialized before the constructor body starts executing, so basically twice the work is done. That also means, if the type of these members don't have default constructor, then your code will notcompile.

因为它们会在构造函数体开始执行之前被初始化,所以基本上完​​成了两倍的工作。这也意味着,如果这些成员的类型没有默认构造函数,那么您的代码将无法编译。

回答by Péter T?r?k

The first one is the recommended best practice, as it is more idiomatic and avoids re-initializing fields for types which do have a default constructor (i.e. non-primitive types).

第一个是推荐的最佳实践,因为它更惯用,并且避免为具有默认构造函数的类型(即非原始类型)重新初始化字段。

When you only initialize a member inside the constructor body, the compiler generates a default member initialization statement for you if it can, so you end up doubly initializing it. This may not be a big deal in some cases, but may be serious performance overhead if constructing the object is expensive.

当你只在构造函数体内部初始化一个成员时,编译器会为你生成一个默认的成员初始化语句,如果可以的话,你最终会重复初始化它。在某些情况下,这可能不是什么大问题,但如果构造对象的成本很高,则可能会造成严重的性能开销。

Update

更新

However, user defined types without a(n explicitly defined or generated) default constructor can't be initialized this way, so a compiler error is produced. The same is true for const and reference fields - these can only be initialized explicitly in the member initializer list.

但是,没有(n 显式定义或生成)默认构造函数的用户定义类型不能以这种方式初始化,因此会产生编译器错误。const 和引用字段也是如此——它们只能在成员初始值设定项列表中显式初始化。

回答by PaperBirdMaster

The only thing to add to Péter T?r?kanswer is that the Initializer List is the only way to initialize const members of objects, i.e.:

唯一要添加到Péter T?r?k答案的是 Initializer List 是初始化对象的 const 成员的唯一方法,即:

class foo
{
public:

    foo(int value)
        : myConstValue(value)
    {};

    foo()
    {
        myConstValue = 0; // <=== Error! myConstValue is const (RValue), you can't assign!
    };

private:
    const int myConstValue;
}

回答by Sanish

In your example code, the first one in constructor initialization and second one is assignment inside constructor body.

在您的示例代码中,构造函数初始化中的第一个和第二个是构造函数体内的赋值。

Constructor initialization list is the best way to do all member initialization because it improves performance.

构造函数初始化列表是进行所有成员初始化的最佳方式,因为它提高了性能。

class A
{
string name;
public:
A(string myname):name(myname) {}
}

In above case compiler will not create a temporary object to do the initialization. However in the following case:

在上述情况下,编译器不会创建临时对象来进行初始化。但是在以下情况下:

A::A()
{
    name = myname;
}

A separate temporary object is created, and this temporary object is passed to string's assignment operator to assign to name. Then the temporary object is destroyed, which is not quite efficient.

创建一个单独的临时对象,并将这个临时对象传递给string的赋值运算符以分配给name。然后临时对象被销毁,效率不高。

Note: It is mandatory that a reference or a const member must be intialized in a constructor initialization list. They cannot be 'assigned' in the body of the constructor.

注意:必须在构造函数初始化列表中初始化引用或 const 成员。它们不能在构造函数的主体中“分配”。

回答by Sanish

Apart from other answers, I would like mention that constructor initialization only for initialize member variables.

除了其他答案,我想提一下构造函数初始化仅用于初始化成员变量。

class Demo
{
    int a;
    int b;
public:
    Demo(int a,int b):a(a),b(b)
    {

    }

};

if we initialize a and b inside constructor it would be self assignment.

如果我们在构造函数中初始化 a 和 b ,它将是自赋值。

回答by DumbCoder

First is initialization, using an initializer list and the second is default construction and then assignment. The first one is at least as fast as the second one and is preferable to the second one.

第一个是初始化,使用初始化列表,第二个是默认构造然后赋值。第一个至少与第二个一样快,并且比第二个更可取。