Ответ
При реаллокации (когда std::vector исчерпывает выделенную capacity) происходит следующее:
- Выделение новой памяти: Аллокатор выделяет новый, больший блок памяти (обычно в 1.5 или 2 раза больше предыдущего).
- Перенос элементов: Все существующие элементы переносятся из старой памяти в новую.
- Если у типа элемента есть небросающий (
noexcept) конструктор перемещения, он будет использован для эффективного переноса ресурсов. - В противном случае используется конструктор копирования.
- Если у типа элемента есть небросающий (
- Уничтожение старых объектов: После успешного переноса все элементы в старой памяти уничтожаются (вызываются их деструкторы), и старая память освобождается.
Критические последствия:
- Инвалидация итераторов и указателей: Все итераторы, указатели и ссылки на элементы вектора становятся невалидными.
- Гарантия исключений: Если используется конструктор перемещения, объявленный как
noexcept(или не бросающий исключений), реаллокация обеспечивает строгую гарантию безопасности исключений. Если перемещение может бросить исключение, используется копирование, что может привести к базовой гарантии (программа остаётся в корректном состоянии, но элементы могут быть утеряны).
Пример:
#include <vector>
#include <string>
int main() {
std::vector<std::string> vec = {"first", "second"}; // capacity может быть 2
vec.push_back("third"); // Триггер реаллокации
// Элементы "first" и "second" перемещаются в новую память,
// так как std::string имеет noexcept move constructor.
// Старая память освобождается.
return 0;
}
Совет: Используйте reserve() для предварительного выделения памяти, если известно примерное количество элементов, чтобы избежать множественных реаллокаций.