Подтвердить что ты не робот

Может ли std::vector переместить свои данные на другой адрес в emplace_back(), хотя все еще неиспользуемое пространство соответствует емкости()?

Гарантируется ли, что std::vector перемещает свои данные только при size()==capacity() и вызывает push_back() или emplace_back() или может это сделать иначе?

4b9b3361

Ответ 1

Спецификация немного косвенная. capacity указывается как:

size_type capacity() const noexcept;

Возвращает: общее количество элементов, которые вектор может удерживать, не требуя перераспределения.

Вторая часть происходит от reserve:

reserve(size_type n);

Замечания: Reallocation делает недействительными все ссылки, указатели и итераторы, ссылающиеся на элементы в последовательность. Перераспределение не должно происходить во время вставок, которые происходят после вызова reserve()до тех пор, пока вставка не сделает размер вектора большим, чем значение capacity().

Из этого можно сделать вывод, что если размер меньше емкости, тогда вставка не вызывает перераспределения.

Нет единственного прямого указания, что вектор не перераспределяется, если есть свободная емкость, и вы явно не называете reserve. Однако в [container.requirements.general] существует общее требование к контейнеру:

Если не указано иное (явно или путем определения функции в терминах других функций), вызов функции-члена контейнера или передача контейнера в качестве аргумента функции библиотеки не приведет к аннулированию итераторов или изменению значений объектов внутри этого контейнера.

Наконец, мы описываем эффекты вставки:

[insert/emplace_back/push_back:]

Примечания: вызывает перераспределение, если новый размер больше старой. Если перераспределение не происходит, все итераторы и ссылки до точки вставки остаются в силе.

Объединяя все вместе: если не указано иное, вызов функции-члена не отменяет итераторов. Перераспределение делает недействительными итераторы (как описано выше в разделе reserve), поэтому, если не указано иное, вызов функции-члена и, в частности, вставки, не перераспределяется. Одна такая переопределяющая спецификация дается для случая, когда новый размер превышает текущая емкость.

Ответ 2

Описание стандарта недостаточно ясно.

$23.3.6.5 векторные модификаторы [vector.modifier]:

Примечания: вызывает перераспределение, если новый размер больше старой. Если перераспределение не происходит, все итераторы и ссылки до момента ввода остаются в силе.

Поэтому при добавлении элементов в std::vector перераспределение, безусловно, произойдет, когда новый размер будет больше текущей емкости, но он не говорит, что перераспределение не произойдет, даже если новый размер меньше или равен текущей емкости. В любом случае, если перераспределение не произойдет, все итераторы и ссылки на элементы перед точкой вставки должны оставаться в силе, означает, что данные не будут перемещены.

То же самое для insert(), emplace_back(), emplace() и push_back().

Цитата из cppreference.com как ссылка:

Если новый size() больше, чем capacity(), то все итераторы и ссылки (включая итератор прошедшего конца) недействительны. В противном случае недействителен только последний итератор конца.