在构造函数-初始化器列表和构造函数体中初始化字段[复制]

时间:2022-11-28 16:36:52

This question already has an answer here:

这个问题已经有了答案:

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.

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

6 个解决方案

#1


44  

They are not the same if member1 and member2 are non-POD (i.e. non-Plain Old Data) types:

如果member1和member2是非pod(即非普通旧数据)类型,则它们不相同:

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 not compile.

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

#2


13  

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.

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

#3


7  

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

唯一要添加到Peter Torok答案的是,初始化器列表是初始化对象的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;
}

#4


4  

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.

创建一个单独的临时对象,并将这个临时对象传递给字符串的赋值操作符以赋值给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成员。它们不能在构造函数的主体中被“分配”。

#5


1  

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.

首先是初始化,使用初始化列表,其次是默认构造,然后是赋值。第一个至少和第二个一样快,比第二个更好。

#6


1  

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,这就是自赋值。

#1


44  

They are not the same if member1 and member2 are non-POD (i.e. non-Plain Old Data) types:

如果member1和member2是非pod(即非普通旧数据)类型,则它们不相同:

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 not compile.

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

#2


13  

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.

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

#3


7  

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

唯一要添加到Peter Torok答案的是,初始化器列表是初始化对象的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;
}

#4


4  

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.

创建一个单独的临时对象,并将这个临时对象传递给字符串的赋值操作符以赋值给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成员。它们不能在构造函数的主体中被“分配”。

#5


1  

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.

首先是初始化,使用初始化列表,其次是默认构造,然后是赋值。第一个至少和第二个一样快,比第二个更好。

#6


1  

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,这就是自赋值。