是直接初始化还是复制初始化?

K.M*_*ier 2 c++ initialization initializer-list c++11 c++14

可以通过多种方式来初始化C ++中的对象(类或结构的实例)。某些语法引起对象的直接初始化,而其他语法则导致复制初始化。随着拷贝省音在编译器中启用,两者具有相同的性能。在禁用复制删除的情况下,当您为每个实例选择复制/初始化时,都会有一个附加的复制/移动构造函数调用(复制初始化)。

结论:复制初始化可能会降低性能!

来自以下问题:C ++ 11成员初始值设定项列表与类初始值设定项?我可以得出结论,这将是复制初始化语法:

obj s = obj("value");
Run Code Online (Sandbox Code Playgroud)

这将是直接初始化语法:

obj s{"value"};
Run Code Online (Sandbox Code Playgroud)

 
但是这个呢?

obj s = {"value"};
Run Code Online (Sandbox Code Playgroud)

还有这个:

obj s = obj{"value"};
Run Code Online (Sandbox Code Playgroud)

还有这个:

obj s("value");
Run Code Online (Sandbox Code Playgroud)

或者这个:

obj s = "value";
Run Code Online (Sandbox Code Playgroud)

注意
Bjarne Stroustrup在他的书“使用C ++编程,原理和实践”第二版,第311页,第9.4.2节中比较了一些初始化样式(但不是全部):

struct Date {
    int y,m,d;                     //year, month, day
    Date(int y, int m, int d);     //check for valid date and initialize
    void add_day(int n);           //increase the Date by n days
};
Run Code Online (Sandbox Code Playgroud)

...

Date my_birthday;                   //error: my_birthday not initialized
Date today{12,24,2007};             //oops! run-time error
Date last{2000,12,31};              //OK (colloquial style)
Date next = {2014,2,14};            //also OK (slightly verbose)
Date christmas = Date{1976,12,24};  //also OK (verbose style)
Run Code Online (Sandbox Code Playgroud)

Stroustrup先生同样提出了这些不同的初始化样式。至少,这就是我的样子。不过,由于本书中尚未讨论这些术语,因此某些可能仍然是直接初始化的,而另一些则是复制初始化的。


编辑
给出的答案带来了一些有趣的东西。
显然,这是直接初始化

obj s("value");
Run Code Online (Sandbox Code Playgroud)

这是直接列表初始化

obj s{"value"};
Run Code Online (Sandbox Code Playgroud)

就像某些人指出的那样,两者之间存在差异。它们实际上有什么不同?在非优化编译器的输出中,差异是否明显?

Nic*_*las 6

obj s = obj("value");
Run Code Online (Sandbox Code Playgroud)

这是一个纯右值的直接初始化,然后用于复制初始化变量s。C++17 的纯右值规则使s.

obj s{"value"};
Run Code Online (Sandbox Code Playgroud)

这是直接列表初始化。“列表”部分很重要。任何时候为了初始化对象而应用花括号初始化列表时,都是在执行列表初始化。

obj s = {"value"};
Run Code Online (Sandbox Code Playgroud)

这是复制列表初始化。

obj s = obj{"value"};
Run Code Online (Sandbox Code Playgroud)

这是一个纯右值的直接列表初始化,然后用于复制初始化变量s

obj s("value");
Run Code Online (Sandbox Code Playgroud)

那就是直接初始化。

obj s = "value";
Run Code Online (Sandbox Code Playgroud)

那就是副本初始化。

Stroustrup 先生将这些不同的初始化风格一视同仁。

他们在做同样的事情的意义上是平等的。但它们在技术上并不相等。复制列表初始化不能调用explicit构造函数。因此,如果选定的构造函数是explicit,则在复制列表初始化的情况下,代码将无法编译。


rus*_*tyx 5

一般来说:

复制初始化中,右侧被隐式转换为类型的临时实例,随后T从该实例s进行复制/移动构造。

Stroustrup先生同样提出了这些不同的初始化样式。

在许多情况下,生成(优化)的代码确实完全相同。编译器被允许的Elid的拷贝构造(即使它有副作用)。现代编译器已经远远超出了诸如此类的简单优化范围,因此您可以有效地依靠这种省略(C ++ 17中需要)。

复制和直接初始化之间的区别非常重要,因为语义是不同的。例如,explicit只能在直接初始化中调用声明的构造函数


1表单T s = {...};复制列表初始化,并遵循一些特殊的列表初始化规则。