将'='添加到初始化列表之间是否有任何细微差别?

时间:2013-08-13 17:13:50

标签: c++ c++11

在C ++ 11中这两种初始化变量的方法之间是否存在细微差别?

  1. vector<double> v { 0.0, 1.1, 2.2, 3.3 };

  2. vector<double> v = { 0.0, 1.1, 2.2, 3.3 };

  3. 后者可以用于与第一个相同的所有情况吗?

    Stroustrup在TCPL4ED中声称第一种方式是唯一可以在每种情况下使用的方式,因此推荐它。后来,他似乎暗示第二个只是写第一个的不同方式。

4 个答案:

答案 0 :(得分:8)

1

vector<double> v { 0.0, 1.1, 2.2, 3.3 };

直接列表初始化。这意味着它是使用构造函数初始化列表初始化的。

构造函数:

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

2

vector<double> v = { 0.0, 1.1, 2.2, 3.3 };

副本列表初始化


标准非常明确:

  

8.5.4列表初始化[dcl.init.list]

     

列表初始化是从braced-init-list初始化对象或引用。这样的初始化程序称为初始化程序列表,列表的逗号分隔的初始化程序子句称为初始化程序列表的元素。初始化列表可以为空。列表初始化可以在直接初始化或copyinitialization上下文中进行;直接初始化上下文中的列表初始化称为直接列表初始化,复制初始化上下文中的列表初始化称为复制列表初始化。 [注意:列表初始化   可以使用:

     
      
  • 作为变量定义中的初始化程序
  •   
     

<强> [...]

     

示例:

  std::complex<double> z{1,2};

  [...]

  std::map<std::string,int> anim = { {"bear",4}, {"cassowary",2}, {"tiger",7} };

对于两者之间的差异,我们应该更进一步:

  

13.3.1.7按列表初始化初始化[over.match.list]

     
      
  • 对于 direct-list-initialization ,候选函数是T类的所有构造函数。
  •   
  • 对于 copy-list-initialization ,候选函数是T的所有构造函数。   但是,如果选择了explicit构造函数,则初始化格式不正确。 [注意:此限制仅适用于此初始化是重载解析的最终结果的一部分 - 结束注释]
  •   

答案 1 :(得分:5)

统一初始化的目的是(部分)删除这两种结构之间的区别。确保它们具有相同的功能。

可悲的是,他们失败了。直接列表初始化(即:T t{...})和复制列表初始化(即:T t = {...})之间只有一个区别。您不需要复制/移动构造函数进行复制列表初始化(尽管名称);第8.5.4节没有将其列为要求。没有一个临时建造的概念可能会被遗弃。它们具有相同的行为,除了

如果选择explicit构造函数,则复制列表初始化将失败。这是唯一的区别。

很难从规范中引用一个引用,因为只有3个提到复制列表初始化是什么。一个是在8.5.4中,它定义了复制列表初始化是列表初始化的一种形式,另一个说明返回一个braced-init-list使用复制列表初始化。 13.3.1.7中的最后一个,它陈述了上述异常:

  

在copy-list-initialization中,如果选择了explicit构造函数,则初始化是不正确的。

所以这是唯一的区别。

答案 2 :(得分:1)

我想到的一个区别是,即使构造函数声明为explicit,第一种形式也可以使用,而第二种形式则不能。抱歉,但@Timothy Shields和@Tomek都错了,两个语句都是直接初始化,而不是复制初始化。

答案 3 :(得分:0)

我猜这与普通构造函数的情况类似(即不使用初始化程序列表)。第一个选择是使用(在这种情况下)构造函数采用初始化列表构造函数的构造。另一个选择是使用初始化列表构造函数创建的临时选项,然后该变量由该复制构造。临时然后消失。请注意,后者通常会跳过临时和复制破坏,因为(N)RVO会启动,但后者要求您的类在定义时具有可访问的复制构造函数。至少这是我记得的C ++ 03,它可能在C ++ 11中有所改变。