Как известно, пустой вектор имеет нулевой размер, вполне очевидно, что библиотека для пустого вектора также устанавливает нулевую емкость. При добавлении элементов в вектор его размер составляет количество добавленных элементов. Емкость будет, по крайней мере совпадать с размером, но может быть и больше. Конкретный объем резервной емкости зависит от реализации библиотеки. В данной конкретной реализации добавление 24 элементов по одному приводит к созданию емкости 32.
Визуально текущее состояние вектора ivec можно представить так:
Теперь при помощи функции reserve() можно зарезервировать дополнительное пространство.
ivec.reserve(50); //
//
//
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;
Вывод свидетельствует о том, что вызов функции reserve() зарезервировал именно столько места, сколько было запрошено:
ivec: size: 24 capacity: 50
Эту резервную емкость можно впоследствии израсходовать следующим образом:
//
while (ivec.size() != ivec.capacity())
ivec.push_back(0);
//
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;
Результат свидетельствует, что в настоящий момент резервная емкость исчерпана, а размер и емкость равны.
ivec: size: 50 capacity: 50
Поскольку использовалась только резервная емкость, в повторном резервировании нет никакой потребности. Фактически, пока не превышена существующая емкость вектора, никакой необходимости в перераспределении его элементов нет.
Если теперь добавить в вектор новый элемент, то последует повторное резервирование памяти.
ivec.push_back(42); //
//
//
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;
Результат выполнения этой части программы имеет следующий вид:
ivec: size: 51 capacity: 100
Он свидетельствует о том, что в данной реализации класса vector использована стратегия удвоения текущей емкости при каждом резервировании новой области памяти.
По мере необходимости можно вызвать функцию shrink_to_fit(), запрашивающую освобождение и возвращение операционной системе памяти, ненужной для текущего размера контейнера:
ivec.shrink_to_fit(); //
//
cout << "ivec: size: " << ivec.size()
<< " capacity: " << ivec.capacity() << endl;
Вызов функции shrink_to_fit() является только запросом; нет никакой гарантии того, что память будет действительно возвращена.
vector может использовать собственную стратегию резервирования. Однако резервирование новой памяти не должно происходить, пока его емкость не исчерпана.
Вектор может начать повторное резервирование только после выполнения пользователем операции вставки, когда размер равен емкости, вызова функции resize() или reserve() со значением, превышающим текущую емкость. Количество памяти, резервируемое свыше указанного объема, зависит от реализации.
Каждая реализация обязана следовать стратегии, гарантирующей эффективное использование функции push_back() при добавлении элементов в вектор. С технической точки зрения время создания элементов вектора составляет время выполнения функции push_back() для первоначально пустого вектора, умноженное на .
Упражнение 9.35. Объясните различие между емкостью вектора и его размером.
Упражнение 9.36. Может ли контейнер иметь емкость, меньшую, чем его размер?
Упражнение 9.37. Почему контейнеры list и array не имеют функции-члена capacity()?
Упражнение 9.38. Напишите программу, позволяющую исследовать рост вектора в библиотеке, которую вы используете.