Что делает std :: make_unique_default_init ()?Разве это не избыточно с std :: make_unique ()? - PullRequest
4 голосов
/ 22 сентября 2019

Похоже, что в C ++ 20 мы получаем некоторые дополнительные служебные функции для интеллектуальных указателей, в том числе:

template<class T> unique_ptr<T> make_unique_default_init();
template<class T> unique_ptr<T> make_unique_default_init(size_t n);

и то же самое для std::make_shared с std::shared_ptr.Почему существующих функций недостаточно:

template<class T, class... Args> unique_ptr<T> make_unique(Args&&... args); // with empty Args
template<class T> unique_ptr<T> make_unique(size_t n);

?Разве существующие не используют конструктор по умолчанию для объекта?

Ответы [ 2 ]

3 голосов
/ 22 сентября 2019

Эти новые функции различаются :

  • Оригинал make_XYZ: Всегда инициализирует указанное значение («явная инициализация», см. §class.expl.init в стандарте ).
  • New make_XYZ_default_init: Выполняет «инициализацию по умолчанию» для указываемого значения (см. § dcl.init, параграф 7 в стандарт );это означает, что фактически не инициализирует для типов, не относящихся к классам и не массивам, на типичных машинах(Да, этот термин немного сбивает с толку.)

Это особенность простых ванильных указателей, которые не были доступны с помощью утилит умных указателей: с обычными указателями вы можете просто выделить, фактически не инициализируяуказанное значение:

T* my_ptr { new int };

Для уникальных / совместно используемых указателей вы можете достичь этого только путем оборачивания существующего указателя, как в:

std::unique_ptr<int[]> my_unique(new int[n]);

теперь у нас есть функция-обертка для этого,

Примечание. См. Соответствующее предложение ISO C ++ WG21 , а также этот ответ SO

2 голосов
/ 23 сентября 2019

allocate_shared, make_shared и make_unique все инициализируют базовый объект, выполняя что-то эквивалентное new T(args...).В случае с нулевым аргументом, который уменьшается до new T(), то есть он выполняет инициализацию значения .Инициализация значений во многих случаях (включая скалярные типы, такие как int и char, их массивы и их совокупности) выполняет нулевую инициализацию - то естьфактическая работа выполняется для обнуления группы данных.

Может быть, вы хотите это, и это важно для вашего приложения, а может, нет.Начиная с P1020R1 , бумаги, в которой были представлены make_unique_default_init, make_shared_default_init и allocate_shared_default_init:

Это не редкость для массивов встроенных типов, таких как unsigned char или double для немедленной инициализации пользователем полностью после выделения.В этих случаях инициализация значений, выполняемая allocate_shared, make_shared и make_unique, является избыточной и снижает производительность, и необходим способ выбора инициализации по умолчанию.

То есть, есливы писали код вроде:

auto buffer = std::make_unique<char[]>(100);
read_data_into(buffer.get());

Инициализация значения, выполняемая make_unique, которая обнуляет эти 100 байтов, совершенно не нужна, так как вы все равно немедленно перезаписываете ее.

Новые функции meow_default_init вместо этого выполняют инициализацию по умолчанию (отсюда и название) - что эквивалентно действию new T (без скобок и скобок).Инициализация по умолчанию в тех случаях, о которых я упоминал ранее (например, int и char, их массивы и их совокупности), не выполняет инициализацию, что экономит время.

Для типов классов, которые имеют предоставленный пользователем конструктор по умолчанию, нет никакой разницы между инициализацией значения и инициализацией по умолчанию: оба просто вызовут конструктор по умолчанию.Но для многих других типов может быть большая разница.

...