Гарантируется ли, что std::vector
перемещает свои данные только при size()==capacity()
и вызывает push_back()
или emplace_back()
или может это сделать иначе?
Может ли std::vector переместить свои данные на другой адрес в emplace_back(), хотя все еще неиспользуемое пространство соответствует емкости()?
Ответ 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()
, то все итераторы и ссылки (включая итератор прошедшего конца) недействительны. В противном случае недействителен только последний итератор конца.