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

时间:2017-10-08 18:54:18

标签: c++ c++11 initialization c++14 initializer-list

可以通过各种方式在C ++中初始化对象(类或结构的实例)。某些语法会引发对象的直接初始化,其他语法会导致复制初始化。在编译器中启用 copy-elision 后,两者都具有相同的性能。禁用 copy-elision 时,如果选择后者(复制初始化),每次实例化时都会有一个额外的复制/移动构造函数调用。

结论:复制初始化可能会产生性能损失!

从以下问题:C++11 member initializer list vs in-class initializer?我可以得出结论,这将是复制初始化语法:

obj s = obj("value");

这将是直接初始化语法:

obj s{"value"};


但是这个怎么样:

obj s = {"value"};

这一个:

obj s = obj{"value"};

这一个:

obj s("value");

或者这个:

obj s = "value";

注意
Bjarne Stroustrup在他的书“使用C ++编程,原理和实践”第2版,第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
};
     

...

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)

先生。 Stroustrup将这些不同的初始化样式表示为相同。至少,这就是它对我的看法。尽管如此,仍有可能有些是直接初始化和其他复制初始化,因为这些术语尚未在书中讨论过。

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

obj s("value");

这是直接列表初始化

obj s{"value"};

正如你们中的一些人指出的那样,存在差异。它们以何种方式实际上有所不同?在非优化编译器的输出中差异是否明显?

3 个答案:

答案 0 :(得分:5)

一般来说:

copy-initialization 中,右侧被隐式转换为T s = ...;类型的临时实例,T随后将从中复制/移动构造

  

先生。 Stroustrup将这些不同的初始化样式表示为相同。

在许多情况下,生成的(优化的)代码确实完全相同。允许编译器elide复制构造(即使它有副作用)。现代编译器远远超出了这样的简单优化,因此你可以有效地依靠这个省略(这在C ++ 17中是必需的)。

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

1 表单explicitcopy-list-initialization,并遵循一些特殊的列表初始化规则。

答案 1 :(得分:4)

obj s = obj("value");

这是prvalue的直接初始化,然后用于复制初始化变量s。 C ++ 17的prvalue规则使得事实上直接初始化s

obj s{"value"};

这是直接 列表 - 初始化。 “列表”部分很重要。无论何时为了初始化对象而应用braced-init-list,都会执行列表初始化。

obj s = {"value"};

这是复制列表初始化。

obj s = obj{"value"};

这是prvalue的直接列表初始化,然后用于复制初始化变量s

obj s("value");

这是直接初始化。

obj s = "value";

那是复制初始化。

  

先生。 Stroustrup将这些不同的初始化样式表示为相同。

他们在大多数情况下完全相同的意义上是平等的。但它们在技术上并不相同; copy-list-initialization不能调用explicit构造函数。因此,如果选定的构造函数是explicit,则代码将无法在copy-list-initialization案例中进行编译。

答案 2 :(得分:2)

您可以轻松look up回答这些问题。也就是说,简单的答案是=表示复制初始化。但是,T t={...}; copy-list-initialization ,除非大括号仅包含T或从中派生的东西,否则不涉及副本!但是,它确实禁止使用非explicit构造函数。