Подтвердить что ты не робот

Должен ли allocator construct() инициализировать по умолчанию вместо инициализации значения?

В качестве продолжения этого вопроса для реализации construct требуется распределитель по умолчанию (std::allocator<T>) (согласно [default.allocator])

template <class U, class... Args>
void construct(U* p, Args&&... args);

Эффекты: ::new((void *)p) U(std::forward<Args>(args)...)

То есть всегда инициализация значений. Результатом этого является то, что std::vector<POD> v(num), для любого типа pod, будет инициализировать значение num элементов, что дороже, чем инициализация по умолчанию элементов num.

Почему & dagger;std::allocator не предоставил дополнительную перегрузку по умолчанию? То есть, что-то вроде (заимствовано из Кейси):

template <class U>
void construct(U* p) noexcept(std::is_nothrow_default_constructible<U>::value)
{
    ::new(static_cast<void*>(p)) U;
}

Была ли причина предпочесть инициализацию значения в случаях вызова? Мне кажется удивительным, что это нарушает обычные правила С++, где мы платим только за то, что хотим использовать.


& dagger; Я предполагаю, что такое изменение невозможно в будущем, учитывая, что в настоящее время std::vector<int> v(100) предоставит вам 100 0 s, но мне интересно, почему это так... учитывая, что так же легко потребовалось бы std::vector<int> v2(100, 0) таким же образом, что существуют различия между new int[100] и new int[100]{}.

4b9b3361

Ответ 1

В С++ 03 Участник-распределитель construct принял два аргумента: указатель и значение, которое было использовано для выполнения инициализации копирования:

20.1.6 Таблица 34

a.construct(p,t)

Эффект:
::new((void*)p) T(t)

construct взятие двух параметров может быть прослежена до 1994 года (стр. 18). Как вы можете видеть, в концепции orignal Степанова это не было частью интерфейса распределителя (он не должен был настраиваться) и присутствовал как оболочка поверх размещения new.

Единственный способ узнать наверняка - спросить самого Степанова, но я полагаю, что эта причина была следующей: если вы хотите что-то построить, вы хотите инициализировать ее с определенным значением. И если вы хотите, чтобы ваши целые числа не инициализировались, вы можете просто опустить вызов construct, поскольку он не нужен для типов POD. Позже construct и другие связанные функции были объединены в распределители, и контейнеры были параметризованы на них, что привело к некоторой потере контроля при инициализации для конечного пользователя.

Таким образом, кажется, что отсутствие инициализации по умолчанию имеет исторические причины: никто, хотя о его важности, когда С++ был стандартизован, а более поздние версии Стандарта не вносили изменения в разрыв.