Аллокаторы, использование метода 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 шт):

Автор решения: AR Hovsepyan

Верно_ 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 не нужен

→ Ссылка