Аллокаторы, использование метода construct()
Переписываю стандартный контейнер std::vector на C++98 с поддержкой std::allocator'а
Мы можем выделять память при помощи _alloc.allocate(), а зачем дальше инициализировать память с помощью _alloc.construct(), нужно ли это делать в случае с вектором, ведь по сути это хранилище ссылок?
Без вызова construct() или с ним, все работает, и примитивы, и пользовательские типы данных , и объекты сохраняются и ими можно пользоваться.
ОБНОВЛЕНИЕ : Немного поэкспериментировал, подскажите почему данный случай отрабатывает нормально:
class User
{
public:
int id;
User(int id) : id(id) {}
};
int main()
{
std::allocator<User> _allocator;
User *objects = _allocator.allocate(3);
User obj1(1);
User obj2(2);
User obj3(3);
objects[0] = obj1;
objects[1] = obj2;
objects[2] = obj3;
_allocator.deallocate(objects, 3);
}
А этот кейс ругается на невалидную работу с памятью uninitialised value внутри objects:
int main()
{
std::allocator<std::string> _allocator;
std::string *objects = _allocator.allocate(3);
std::string obj1("1");
std::string obj2("2");
std::string obj3("3");
objects[0] = obj1;
objects[1] = obj2;
objects[2] = obj3;
_allocator.deallocate(objects, 3);
}
Ответы (1 шт):
Верно_ allocate выделяет сырую память(там нет объектов) для количества элементов, указанных в ее аргументе. Но не забывайте, что этот аргумент зависит от реализации вектора.
Стандартный вектор ведь просит своему распределителю выделять память побольше, чем требуется для размещения элементов(это есть capacity вектора), но конструировать конкретное количество объектов_элементов вектора.
Например для 17 элементов, allocate может выделить память, например, под 24 элемента. Это означает, что данная функция_член вектора вызывает _alloc.allocate(24), а потом туда вставляет объекты вызовом _alloc.construct(адрес и значения для конструирования объекта).
Реализация может быть разная, но construct(T* p, Type arg) примерно может делать, грубо говоря, следующее:
new(p)T(arg) //поместить T(arg) по адресу p
Если вы реализуете распределитель и стратегию вектора по другому, то может ваш _alloc.allocate() выделит память под массив конкретных объектов, тогда да _ он заодно выполняет и конструирование, и метод construct не нужен