//
//
return {data, uninitialized_copy(b, e, data)};
}
Функция alloc_n_copy() вычисляет объем резервируемого пространства, вычитая указатель на первый элемент из указателя на следующий после последнего. Зарезервировав память, функция создает в ней копии заданных элементов.
Копирование осуществляется в операторе return при списочной инициализации возвращаемого значения (см. раздел 6.3.2). Указатель-член first возвращенной пары указывает на начало зарезервированной памяти; значение для указателя-члена second возвращается функцией uninitialized_copy() (см. раздел 12.2.2). Это значение будет указателем на следующий элемент после последнего созданного элемента.
free()У функции-члена free() две обязанности: она должна удалить элементы, а затем освободить пространство, зарезервированное объектом класса StrVec. Цикл for вызывает функцию destroy() класса allocator, перебирая элементы в обратном порядке, начиная с последнего существующего элемента и заканчивая первым:
void StrVec::free() {
//
//
if (elements) {
//
for (auto p = first_free; p != elements; /* пусто */)
alloc.destroy(--p);
alloc.deallocate(elements, cap - elements);
}
}
Функция destroy() запускает деструктор класса string. Деструктор класса string освобождает память, занятую самой строкой.
Как только элементы будут удалены, освобождается пространство, зарезервированное классом StrVec при вызове функции deallocate(). Указатель, передаваемый функции deallocate(), должен быть именно тем, который ранее создал вызов функции allocate(). Поэтому перед вызовом функции deallocate() сначала проверяется, тот ли это elements, а не нулевой.
При наличии функций-членов alloc_n_copy() и free() функции-члены управления копированием нашего класса очень просты.
StrVec::StrVec(const StrVec &s) {
//
//
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
Конструктор копий вызывает функцию alloc_n_copy(), а затем присваивает результат вызова переменным-членам. Возвращаемое значение функции alloc_n_copy() является парой указателей. Первый указатель указывает на первый созданный элемент, а второй — на следующий после последнего созданного. Поскольку функция alloc_n_copy() резервирует пространство для точно такого количества элементов, которое было задано, указатель cap также указывает только на следующий после последнего созданного.
Деструктор вызывает функцию free():
StrVec::~StrVec() { free(); }
Оператор присвоения копии вызывает функцию alloc_n_copy() прежде, чем освободить существующие элементы. Это защищает от копирования в себя самого:
StrVec &StrVec::operator=(const StrVec &rhs) {
//
//
auto data = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = data.first;
first_free = cap = data.second;
return *this;
}
Подобно конструктору копий, оператор присвоения копии использует значения, возвращенные функцией alloc_n_copy(), для инициализации своих указателей.
Прежде чем приступить к функции reallocate(), следует обдумать то, что она должна делать:
• зарезервировать память для нового, большего массива строк;
• заполнить первую часть этого пространства существующими элементами;
• удалить элементы в существующей памяти и освободить ее.