C ++ 11成员初始化列表vs类初始化器? [英] C++11 member initializer list vs in-class initializer?

查看:187
本文介绍了C ++ 11成员初始化列表vs类初始化器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C ++ 11中初始化对象成员变量的方法有什么区别?还有别的办法吗?哪种方式更好(性能)?:

What difference between these ways of initializing object member variables in C++11 ? Is there another way ? which way is better (performance) ?:

class any {
  public:
    obj s = obj("value");
    any(){}
};

class any {
  public:
    obj s;
    any(): s("value"){}
};

谢谢。

推荐答案

不,这些不一样

它们之间的区别是相同的,适用于 direct - 初始化复制初始化,这是微妙的但通常很混乱。

The difference between them is the same that applies for direct-initialization vs. copy-initialization, which is subtle but often very confusing.

§12.6.2[class.base .init]:

§12.6.2 [class.base.init]:



  1. 用于初始化指定的子对象(或者在委托构造函数的情况下是完整的类对象)中的 braced-init-list [...]

  1. The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of 8.5 for direct-initialization. [...]

在非委托构造函数中,如果给定的非静态数据成员或基类不是由mem-initializer-id 指定的(包括没有 mem-initializer-list 的情况,因为构造函数没有 ctor-initializer ),且实体不是抽象类(10.4)的虚拟基类,则

In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then

是具有括号或初始值的实体的非静态数据成员,实体按第8.5节中所述初始化 ;

— if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;


§8.5[dcl.init]:

§8.5 [dcl.init]:



  1. The initialization that occurs in the form

T x = a; p>

T x = a;

以及参数传递,函数返回,抛出异常(15.1),处理异常(15.3)聚合成员初始化(8.5.1)称为复制初始化

as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization.

初始化非静态数据成员在 member-initializer-list 上遵循直接初始化的规则,其不创建需要移动/复制的中间临时em> copy-elision ),数据成员的类型都不能是可复制/可移动的(即使复制被省略)。此外,直接初始化引入显式上下文,而复制初始化是非显式的(如果为初始化选择的构造函数显式,程序将不会编译)。

Initializing a non-static data member on a member-initializer-list follows the rules of direct-initialization, which doesn't create intermediate temporaries that need to be moved/copied (if compiled without a copy-elision), neither the type of the data member must be copyable/movable (even if the copy is elided). In addition, a direct-initialization introduces an explicit context, while a copy-initialization is non-explicit (if a constructor selected for the initialization is explicit, the program won't compile).

换句话说, obj s = obj );如果 obj 声明为

struct obj
{
    obj(std::string) {}
    obj(const obj&) = delete;
};

或:

struct obj
{
    obj(std::string) {}
    explicit obj(const obj&) {}
};

作为一个更有形的例子,下面的代码不能编译:

As a more tangible example, while the below won't compile:

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) {}
};








哪种方式更好(性能)?

相同性能。在禁用 copy-elision 时,当使用复制初始化语法时,每次实例化都有一个额外的复制/移动构造函数调用( obj = obj(value); 是以下之一。

With a copy-elision enabled both have identical performance. With copy-elision disabled, there is an additional copy/move constructor call upon every instantiation when the copy-initialization syntax is used (that obj s = obj("value"); is one of).


有另一种方法吗?

/ em>语法允许执行直接列表初始化

The brace-or-equal-initializer syntax allows one to perform a direct-list-initialization as well:

class any {
public:
    obj s{ "value" };
    any() {}
};








还有其他差异吗?

值得一提的其他差异是:

Some other differences that are worth mentioning are:


  1. Brace-or-equal-initializer 必须与类声明一起驻留在头文件中。

  2. 如果两者都合并, member-initializer-list 的优先级高于 brace-or-equal-initializer (即 / em>被忽略)。

  3. (C ++ 11,直到C ++ 14)使用大括号或等于初始化器

  1. Brace-or-equal-initializer must reside in a header file along with a class declaration.
  2. If both are combined, member-initializer-list takes priority over brace-or-equal-initializer (that is, brace-or-equal-initializer is ignored).
  3. (C++11 only, until C++14) A class that uses brace-or-equal-initializer violates constraints for an aggregate type.
  4. With the brace-or-equal-initializer syntax it's not possible to perform a direct-initialization other than a direct-list-initialization.

这篇关于C ++ 11成员初始化列表vs类初始化器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆