Гарантируется ли стандартом порядок инициализации векторных элементов?

Чтобы заполнить std::vector<struct_name>из 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;
   //...
}

Но сегодня я нашел другой способ сделать это с помощью конструктора по умолчанию:

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

int main()
{
    std::size_t n;
    std::cin>>n; 
    std::vector<point> vec(n);
    //...
}

Вопросы:

  1. Гарантируется ли порядок инициализации элементов вектора стандартом (0,1,2,n-1...)?
  2. (Если ответ на предыдущий вопрос верен) Действительно ли второй вариант имеет двойную эффективность?

Меня интересует поведение в соответствии со стандартом С++ 11 (и новее)

2 ответа

Не гарантируется, что элементы инициализируются в порядке их индексов. В С++ 11 см. [vector.cons]/3:

Эффекты: Создает vectorс nэлементы, инициализируемые значением.

Это ничего не говорит о заказе, поэтому ничего нельзя предположить. Формулировка меняется в более поздних редакциях стандарта, но, похоже, порядок никогда не навязывался.

По вашему первому вопросу, C++20(но это восходит к C++11также) раздел, посвященный контейнеру последовательности, не дает обещаний о порядке, в котором элементы создаются внутри самого вектора, только то, что элементам присваивается определенное значение:

Эффекты: Создает vectorс nэлементы, вставленные по умолчанию.

Ничего о порядке в этом (очень кратком) разделе (а) .

Но у вас есть большая проблема с вашим методом, в частности, я не думаю, что вы действительно хотите выйти на улицу .cinдля каждого случая, когда вы по умолчанию создаете точечную переменную.

Например, могут быть случаи, когда вам нужна временная переменная, созданная по умолчанию, и это будет рассматриваться как зависание, если ваша программа внезапно перестанет принимать пользовательский ввод, особенно без какого-либо запроса пользователю :-)


Это делает ваш второй вопрос спорным, но, если вас беспокоит неэффективность инициализации векторных элементов, а затем их изменение с помощью цикла ввода, я бы не стал. Структура без конструктора (т.е. всего пара intпеременных) не нужно их инициализировать (b) , поэтому вектор из них может просто выполнить распределение и остановиться на этом.


(a) Некоторый порядок гарантируется стандартом, например, порядок разрозненных элементов в классе или порядок элементов в массиве. Однако элементы вектора не являются ни тем, ни другим.


(б) Это описано в C++20 10.9 Iniitialisation [class.init]:

Когда инициализатор не указан для объекта типа класса (возможно, cv-qualified) (или его массива) или инициализатор имеет форму , объект инициализируется, как указано в 9.3.

а также C++20 9.3 Initializers [dcl.init]:

Инициализация по умолчанию объекта типа означает:

  • Если это тип класса (возможно, cv-qualified), рассматриваются конструкторы. Перечислены применимые конструкторы, и лучший из них для инициализатора ()выбирается через разрешение перегрузки. Выбранный таким образом конструктор вызывается с пустым списком аргументов для инициализации объекта.
  • Если Tявляется типом массива, каждый элемент инициализируется по умолчанию.
  • В противном случае инициализация не выполняется.

Это первый пункт, который имеет значение для типа без явно определенных или унаследованных конструкторов. В этом случае он использует неявно определенный конструктор, который эквивалентен определяемому пользователем конструктору без тела и списка инициализаторов.

Другие вопросы по тегам