可以通过各种方式在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"};
正如你们中的一些人指出的那样,存在差异。它们以何种方式实际上有所不同?在非优化编译器的输出中差异是否明显?
答案 0 :(得分:5)
一般来说:
&state=
或T s(...);
为direct-initialization T s{...};
是copy-initialization 1 在 copy-initialization 中,右侧被隐式转换为T s = ...;
类型的临时实例,T
随后将从中复制/移动构造
先生。 Stroustrup将这些不同的初始化样式表示为相同。
在许多情况下,生成的(优化的)代码确实完全相同。允许编译器elide复制构造(即使它有副作用)。现代编译器远远超出了这样的简单优化,因此你可以有效地依靠这个省略(这在C ++ 17中是必需的)。
复制和直接初始化之间的区别非常重要,因为语义是不同的;例如,只能在 direct-initialization 中调用声明为s
的构造函数。
1 表单explicit
为copy-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
构造函数。