标准是否保证了向量元素的初始化顺序?

Pav*_*Dev 11 c++ language-lawyer

为了填充std::vector<struct_name>from std::cin,我通常写如下代码:

struct point{
    int x, y;
};

int main()
{
   std::size_t n;
   std::cin>>n; 
   std::vector<point> vec(n);
    for (auto& p:vec) 
        std::cin>>p.x>>p.y;
   //...
}
Run Code Online (Sandbox Code Playgroud)

但是今天我发现了另一种使用默认构造函数的方法:

struct point{
int x, y;
   point(){
      std::cin>>x>>y;
   }
};

int main()
{
    std::size_t n;
    std::cin>>n; 
    std::vector<point> vec(n);
    //...
}
Run Code Online (Sandbox Code Playgroud)

问题

  1. 向量元素的初始化顺序是否由标准(0,1,2,n-1...)保证?
  2. (如果上一个问题的答案是正确的)第二个变体真的有两次有效吗?

我对根据 C++11(和更新的)标准的行为感兴趣

Bri*_*ian 13

不能保证元素按其索引的顺序进行初始化。在 C++11 中,请参阅 [vector.cons]/3:

效果:构造一个vector具有n值初始化的元素。

这对排序没有任何说明,因此不能假设任何内容。该标准的后续版本中的措辞发生了变化,但似乎从未强加过任何顺序。


pax*_*blo 6

关于您的第一个问题,处理序列容器的C++20(但这也可以追溯到C++11)部分承诺在向量本身内构造元素的顺序,只是将元素设置为某个特定值:vector

效果:vector使用n默认插入的元素构造一个。

对那个(非常简短的)部分(a) 中的顺序一无所知。

但是你的方法有一个更大的问题,特别是我不认为你真的cin在默认构造点变量的每种情况下都去。

例如,在某些情况下,您需要一个默认构造的临时变量,如果您的程序突然停止接受用户输入,它会被视为挂起,尤其是在没有向用户提示的情况下:-)


这让你的第二个问题没有实际意义,但是,假设你担心初始化向量元素的效率低下,然后用输入循环改变它们,我不会。没有构造函数的结构(即,只有几个int变量)不需要初始化它们(b),因此它们的向量可以进行分配并在那里停止。


(a)中的一些命令在标准保证的,例如不同的构件的一类中的顺序,或一个阵列内的元件的顺序。然而,向量的元素都不是这些东西。


(b)这包括在C++20 10.9 Iniitialisation [class.init]

当没有为(可能是 cv 限定的)类类型(或其数组)()的对象指定初始值设定项时,或初始值设定项的形式为 时,对象将按照 中指定的方式进行初始化9.3

C++20 9.3 Initializers [dcl.init]

默认初始化一个类型的对象T意味着:

  • 如果T是(可能是 cv 限定的)类类型,则考虑构造函数。枚举适用的构造函数,并()通过重载决议选择最佳构造函数。如此选择的构造函数被调用,参数列表为空,以初始化对象。
  • 如果T是数组类型,则每个元素都是默认初始化的。
  • 否则,不执行初始化。

对于没有显式定义或继承的构造函数的类型,这是第一个要点。在这种情况下,它使用隐式定义的构造函数,相当于没有主体和初始化列表的用户定义的构造函数。