C++ 在这种特定情况下,使用成员初始值设定项列表和在构造函数中赋值之间有区别吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4589237/
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-28 15:51:15  来源:igfitidea点击:

In this specific case, is there a difference between using a member initializer list and assigning values in a constructor?

c++initializationinitialization-list

提问by Stef

Internally and about the generated code, is there a really difference between :

在内部和关于生成的代码之间,是否真的有区别:

MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}

and

MyClass::MyClass()
{
  _capacity=15;
  _data=NULL;
  _len=0
}

thanks...

谢谢...

采纳答案by templatetypedef

Assuming that those values are primitive types, then no, there's no difference. Initialization lists only make a difference when you have objects as members, since instead of using default initialization followed by assignment, the initialization list lets you initialize the object to its final value. This can actually be noticeably faster.

假设这些值是原始类型,那么不,没有区别。初始化列表仅在您将对象作为成员时才起作用,因为不是使用默认初始化然后赋值,初始化列表允许您将对象初始化为其最终值。这实际上可以明显更快。

回答by stefanB

You need to use initialization list to initialize constant members,references and base class

您需要使用初始化列表来初始化常量成员、引用和基类

When you need to initialize constant member, references and pass parameters to base class constructors, as mentioned in comments, you need to use initialization list.

当您需要初始化常量成员、引用和传递参数给基类构造函数时,如注释中所述,您需要使用初始化列表。

struct aa
{
    int i;
    const int ci;       // constant member

    aa() : i(0) {} // will fail, constant member not initialized
};

struct aa
{
    int i;
    const int ci;

    aa() : i(0) { ci = 3;} // will fail, ci is constant
};

struct aa
{
    int i;
    const int ci;

    aa() : i(0), ci(3) {} // works
};

Example (non exhaustive) class/struct contains reference:

示例(非详尽)类/结构包含参考:

struct bb {};

struct aa
{
    bb& rb;
    aa(bb& b ) : rb(b) {}
};

// usage:

bb b;
aa a(b);

And example of initializing base class that requires a parameter (e.g. no default constructor):

以及初始化需要参数的基类的示例(例如,没有默认构造函数):

struct bb {};

struct dd
{
    char c;
    dd(char x) : c(x) {}
};

struct aa : dd
{
    bb& rb;
    aa(bb& b ) : dd('a'), rb(b) {}
};

回答by Richard Cook

Yes. In the first case you can declare _capacity, _dataand _lenas constants:

是的。在第一种情况下,您可以将_capacity,_data和声明_len为常量:

class MyClass
{
private:
    const int _capacity;
    const void *_data;
    const int _len;
// ...
};

This would be important if you want to ensure const-ness of these instance variables while computing their values at runtime, for example:

如果您想const在运行时计算它们的值时确保这些实例变量的完整性,这将很重要,例如:

MyClass::MyClass() :
    _capacity(someMethod()),
    _data(someOtherMethod()),
    _len(yetAnotherMethod())
{
}

constinstances mustbe initialized in the initializer list orthe underlying types must provide public parameterless constructors (which primitive types do).

const实例必须在初始化器列表中初始化,或者基础类型必须提供公共无参数构造函数(原始类型可以)。

回答by user929404

I think this link http://www.cplusplus.com/forum/articles/17820/gives an excellent explanation - especially for those new to C++.

我认为这个链接http://www.cplusplus.com/forum/articles/17820/给出了一个很好的解释 - 特别是对于那些 C++ 新手。

The reason why intialiser lists are more efficient is that within the constructor body, only assignments take place, not initialisation. So if you are dealing with a non-built-in type, the default constructor for that object has already been called before the body of the constructor has been entered. Inside the constructor body, you are assigning a value to that object.

初始化列表更有效的原因是在构造函数体内,只发生赋值,而不是初始化。因此,如果您正在处理非内置类型,则该对象的默认构造函数在构造函数体被输入之前已经被调用。在构造函数体内,您正在为该对象分配一个值。

In effect, this is a call to the default constructor followed by a call to the copy-assignment operator. The initialiser list allows you to call the copy constructor directly, and this can sometimes be significantly faster (recall that the initialiser list is before the body of the constructor)

实际上,这是对默认构造函数的调用,然后是对复制赋值运算符的调用。初始化列表允许您直接调用复制构造函数,这有时会明显更快(回想一下初始化列表在构造函数主体之前)

回答by Fred Larson

I'll add that if you have members of class type with no default constructor available, initialization is the only way to construct your class.

我要补充一点,如果您有没有可用默认构造函数的类类型成员,则初始化是构造类的唯一方法。

回答by Mark Ransom

A big difference is that the assignment can initialize members of a parent class; the initializer only works on members declared at the current class scope.

一个很大的区别是赋值可以初始化父类的成员;初始值设定项仅适用于在当前类范围内声明的成员。

回答by Puppy

Depends on the types involved. The difference is similar between

取决于所涉及的类型。两者之间的区别是相似的

std::string a;
a = "hai";

and

std::string a("hai");

where the second form is initialization list- that is, it makes a difference if the type requires constructor arguments or is more efficient with constructor arguments.

其中第二种形式是初始化列表——也就是说,如果类型需要构造函数参数或者使用构造函数参数更有效,它会有所不同。

回答by lukmac

The real difference boils down to how the gcc compiler generate machine code and lay down the memory. Explain:

真正的区别归结为 gcc 编译器如何生成机器代码并放置内存。解释:

  • (phase1) Before the init body (including the init list): the compiler allocate required memory for the class. The class is alive already!
  • (phase2) In the init body: since the memory is allocated, every assignment now indicates an operation on the already exiting/'initialized' variable.
  • (phase1) 在init体之前(包括init列表):编译器为类分配所需的内存。班级已经活了!
  • (phase2) 在 init 主体中:由于内存已分配,现在每个赋值都指示对已退出/“已初始化”变量的操作。

There are certainly other ways to handle const type members. But to ease their life, the gcc compiler writers decide to set up some rules

当然还有其他方法来处理 const 类型成员。但是为了让他们的生活更轻松,gcc 编译器作者决定设置一些规则

  1. const type members must be initialized before the init body.
  2. After phase1, any write operation only valid for non-constant members.
  1. const 类型成员必须在 init 主体之前初始化。
  2. 在第一阶段之后,任何写操作只对非常量成员有效。

回答by CB Bailey

There is only one way to initializebase class instances and non-static member variables and that is using the initializer list.

只有一种方法可以初始化基类实例和非静态成员变量,那就是使用初始化列表。

If you don't specify a base or non-static member variable in your constructor's initializer list then that member or base will either be default-initialized (if the member/base is a non-POD class type or array of non-POD class types) or left uninitialized otherwise.

如果您没有在构造函数的初始值设定项列表中指定基类或非静态成员变量,则该成员或基类将被默认初始化(如果成员/基类是非 POD 类类型或非 POD 类的数组)类型)或未初始化。

Once the constructor body is entered, all bases or members will have been initialized or left uninitialized (i.e. they will have an indeterminate value). There is no opportunity in the constructor body to influence how they should be initialized.

一旦进入构造函数体,所有基类或成员都将被初始化或未初始化(即它们将具有不确定的值)。构造函数体中没有机会影响它们应该如何初始化。

You may be able to assign new values to members in the constructor body but it is not possible to assign to constmembers or members of class type which have been made non-assignable and it is not possible to rebind references.

您可能能够为构造函数体中的成员分配新值,但无法分配给不可分配的const成员或类类型的成员,并且无法重新绑定引用。

For built in types and some user-defined types, assigning in the constructor body may have exactly the same effect as initializing with the same value in the initializer list.

对于内置类型和一些用户定义的类型,在构造函数体中赋值可能与使用初始化列表中的相同值进行初始化具有完全相同的效果。

If you fail to name a member or base in an initializer list and that entity is a reference, has class type with no accessible user-declared default constructor, is constqualified and has POD type or is a POD class type or array of POD class type containing a constqualified member (directly or indirectly) then the program is ill-formed.

如果您未能在初始化列表中命名成员或基类,并且该实体是引用、具有没有可访问的用户声明的默认构造函数的类类型、经过const限定且具有 POD 类型或者是 POD 类类型或 POD 类类型的数组包含const合格成员(直接或间接),则程序格式错误。

回答by L. Vicente Mangas

If you write an initializer list, you do all in one step; if you don't write an initilizer list, you'll do 2 steps: one for declaration and one for asign the value.

如果你写了一个初始化列表,你可以一步完成;如果您不编写初始化程序列表,您将执行 2 个步骤:一个用于声明,另一个用于赋值。