在C ++ 11中初始化对象成员变量的这些方法有何不同?还有另外一种方法吗?哪种方式更好(性能)?:
class any {
public:
obj s = obj("value");
any(){}
};
或
class any {
public:
obj s;
any(): s("value"){}
};
感谢。
答案 0 :(得分:37)
不,这些不一样。
它们之间的区别与适用于直接初始化与复制初始化的区别相同,这是微妙但通常非常混乱。
§12.6.2[class.base.init]:
mem-initializer 中的表达式列表或 braced-init-list 用于初始化指定的子对象(或者,在委托构造函数的情况下,完整的类对象)根据8.5的初始化规则进行直接初始化。 [...]
- 醇>
在非委托构造函数中,如果给定的非静态数据成员或基类未由 mem-initializer-id 指定(包括没有<的情况) em> mem-initializer-list 因为构造函数没有 ctor-initializer )并且实体不是抽象类的虚拟基类(10.4),那么
- 如果实体是具有大括号或等于初始化的非静态数据成员,则按照8.5 中的规定初始化;
§8.5[dcl.init]:
- 醇>
以
形式出现的初始化T x = a;
以及参数传递,函数返回,抛出异常(15.1),处理异常(15.3)和聚合成员初始化(8.5.1)称为复制初始化。< / p>
在 member-initializer-list 上初始化非静态数据成员遵循 direct-initialization 的规则,该规则不会创建需要的中间临时值移动/复制(如果没有 copy-elision 编译),数据成员的类型都不能是可复制/可移动的(即使复制被删除)。此外,直接初始化引入了显式上下文,而复制初始化是非显式的(如果为初始化选择的构造函数是explicit
,该程序将无法编译。)
换句话说,如果将obj s = obj("value");
声明为obj
,则struct obj
{
obj(std::string) {}
obj(const obj&) = delete;
};
语法将无法编译:
struct obj
{
obj(std::string) {}
explicit obj(const obj&) {}
};
或:
struct any
{
std::atomic<int> a = std::atomic<int>(1); // ill-formed: non-copyable/non-movable
std::atomic<int> b = 2; // ill-formed: explicit constructor selected
};
作为一个更切实的例子,虽然下面不会编译:
struct any
{
std::atomic<int> a;
std::atomic<int> b{ 2 };
any() : a(1) {}
};
这个会:
obj s = obj("value");
哪种方式更好(性能)?
启用 copy-elision 后,两者的性能相同。禁用 copy-elision 后,在使用 copy-initialization 语法时,每次实例化时都会有一个额外的复制/移动构造函数调用(class any {
public:
obj s{ "value" };
any() {}
};
是其中之一)。
还有其他办法吗?
brace-or-equal-initializer 语法允许用户执行直接列表初始化:
{{1}}
还有其他差异吗?
值得一提的其他一些差异是:
答案 1 :(得分:7)
这两个例子都是等同的 虽然只有这种类型是可复制的或可移动的(自己检查)并且NRVO实际上已经完成(任何中途不错的编译器都会这样做)。
虽然如果你有许多构造函数和构造函数链接是不合适的,第一种方法将允许你不要重复自己。
此外,您可以使用该方法定义聚合,其默认值不同于自C ++ 14以来(部分)成员的聚合初始化。
答案 2 :(得分:3)
他们是一样的。
在性能方面,两者都不比另一方好,并且没有其他方法可以初始化它们。
类内初始化(在您的示例中的第一个)的好处是初始化的顺序是隐含的。在初始化列表中,您必须明确说明订单 - 如果订单不正确,编译器将发出无序初始化警告。
来自标准:
12.6.2.5
nonstatic data members shall be initialized in the order they were declared
in the class definition
如果您的清单中的订单有误,GCC会抱怨:
main.cpp: In constructor 'C::C()':
main.cpp:51:9: warning: 'C::b' will be initialized after
main.cpp:51:6: warning: 'int C::a'
初始化列表的好处可能只是一种品味 - 列表是显式的,通常在源文件中。 In-class是隐式的(可以说是),通常在头文件中。