繁体   English   中英

使用双花​​括号进行矢量初始化:std :: string vs int

[英]Vector initialization with double curly braces: std::string vs int

在回答这个问题时: 使用双花​​括号初始化vector <string>

它表明

vector<string> v = {{"a", "b"}};

将使用带有一个元素initializer_list调用std::vector构造initializer_list 因此,向量中的第一个(也是唯一的)元素将由{"a", "b"} 这会导致未定义的行为,但这超出了这一点。

我发现的是

std::vector<int> v = {{2, 3}};

将使用两个元素initializer_list调用std::vector构造initializer_list

为什么这种行为差异的原因?

行为的差异是由于默认参数。 std::vector有这个c'tor:

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

注意第二个参数。 {2, 3}推导为std::initializer_list<int> (不需要初始化器的转换)并且分配器是默认的。

类类型列表初始化的规则基本上是:首先,只考虑std::initializer_list构造函数进行重载解析,然后在必要时对所有构造函数执行重载解析(这是[over.match.list] )。

当从初始化列表初始化std::initializer_list<E> ,就好像我们从初始化列表中的N个元素(来自[dcl.init.list] / 5 )中实现了一个const E[N]

对于vector<string> v = {{"a", "b"}}; 我们首先尝试使用initializer_list<string>构造函数,这将涉及尝试初始化1个const string的数组,其中一个string{"a", "b"}初始化的。 这是可行的,因为string的迭代器对构造函数,所以我们最终得到一个包含一个单独字符串的向量(这是UB,因为我们违反了该字符串构造函数的前提条件)。 这是一个简单的案例。


对于vector<int> v = {{2, 3}}; 我们首先尝试使用initializer_list<int>构造函数,这将涉及尝试初始化1个const int的数组,其中一个int{2, 3}初始化。 不可行

那么,考虑到所有的vector构造函数,我们重做重载决策。 现在,我们得到两个可行的构造函数:

  • vector(vector&& ) ,因为当我们递归初始化参数时,初始化列表将是{2, 3} - 我们将尝试初始化2 const int的数组,这是可行的。
  • vector(std::initializer_list<int> ) ,再次。 这一次不是从正常列表初始化的世界,但只是直接初始化initializer_list从同{2, 3}初始化列表,这是可行出于同样的原因。

要选择哪个构造函数,我们必须进入[over.ics.list] ,其中vector(vector&& )构造函数是用户定义的转换序列,vector(initializer_list<int> )构造函数是identity ,因此它是首选。


为了完整性, vector(vector const&)也是可行的,但出于其他原因,我们更喜欢移动构造函数到复制构造函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM