Требуется ли сохранение емкости при перемещении std::vector? - программирование

Требуется ли сохранение емкости при перемещении std::vector?

Рассмотрим следующий код:

std::vector vec;
vec.reserve(500);
size_t cap = vec.capacity();

std::vector newVec = std::move(vec);
assert(cap == newVec.capacity());

В значительной степени любая реализация, с которой вы сталкиваетесь, будет работать. Меня не волнует, что такое реализация. Я хочу знать, что требует стандарт. Будет ли перемещенная на vector та же емкость, что и оригинал? Или будет триггер assert?

4b9b3361

Ответ 1

Посмотрев на стандарт, кажется, что ничего не требуется от конструктора перемещения, однако, как говорит @amaurea, он полностью победит цель семантики перемещения, если конструктор перемещения должен попытаться выделить или освободить память, поэтому я бы ожидайте, что емкость останется неизменной во всех реализациях.


23.2.1 Общие требования к контейнерам

Выражение

X u(a);
X u = a;

Утверждение/примечание pre-/post-condition

Требуется: T является CopyInsertable в X (см. ниже).
сообщение: u == a


Стандарт требует только newVec == vec. Поскольку емкость не учитывается для std::vector::operator==, newVec необязательно должна иметь такую ​​же емкость, как vec.

Ответ 2

Стандартные требования С++ 11 для конструктора перемещения для std::vector (Таблица 99 - Требования к контейнерам, поддерживающие Allocator):

X(rv)
X u(rv)
  • перемещение конструкции распределителя не должно выходить через исключение
  • post: u должен иметь те же элементы, что и rv до этой конструкции; значение get_allocator() должно быть таким же, как значение rv.get_allocator() до этой конструкции.
  • сложность: постоянная

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

С другой точки зрения, если перемещенный вектор пуст, вполне законно просто игнорировать его и строить по умолчанию. Это все равно будет O (1), так как оно не требует каких-либо конструкций для элементов. (Спасибо Николь Болас за этот вопрос).

Кроме того, реализация может уменьшить емкость до размера с помощью параметра hint функции std::allocator::allocate:

pointer allocate(size_type, allocator<void>::const_pointer hint = 0);

Использование hint не указывается, но предназначено для помощи местностям, если такая реализация так желательна. Таким образом, некоторое сложное решение, возможно, могло бы переносить указатель на векторный носитель как hint и использовать realloc для уменьшения емкости.

Вывод: выглядит стандартным, не гарантирует сохранение емкости при перемещении std::vector, потенциально может быть сжато хранилище.