Гарантируется ли стандартом порядок инициализации векторных элементов?
Чтобы заполнить
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);
//...
}
Вопросы:
- Гарантируется ли порядок инициализации элементов вектора стандартом (0,1,2,n-1...)?
- (Если ответ на предыдущий вопрос верен) Действительно ли второй вариант имеет двойную эффективность?
Меня интересует поведение в соответствии со стандартом С++ 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
является типом массива, каждый элемент инициализируется по умолчанию.- В противном случае инициализация не выполняется.
Это первый пункт, который имеет значение для типа без явно определенных или унаследованных конструкторов. В этом случае он использует неявно определенный конструктор, который эквивалентен определяемому пользователем конструктору без тела и списка инициализаторов.