Зачем использовать std :: make_unique в C ++ 17? - PullRequest
0 голосов
/ 20 декабря 2018

Насколько я понимаю, в C ++ 14 введено std::make_unique, потому что из-за того, что порядок оценки параметров не указан, это было небезопасно:

f(std::unique_ptr<MyClass>(new MyClass(param)), g()); // Syntax A

(Пояснение: если оценкасначала выделяет память для необработанного указателя, затем вызывает g(), и перед конструкцией std::unique_ptr генерируется исключение, затем происходит утечка памяти.)

Вызов std::make_unique был способом ограничения вызовапорядок, таким образом делая вещи безопасными:

f(std::make_unique<MyClass>(param), g());             // Syntax B

С тех пор C ++ 17 уточнил порядок оценки, сделав синтаксис A также безопасным, поэтому вот мой вопрос: все еще естьпричина использовать std::make_unique над конструктором std::unique_ptr в C ++ 17?Можете ли вы привести несколько примеров?

На данный момент единственная причина, которую я могу себе представить, состоит в том, что она позволяет набирать MyClass только один раз (при условии, что вам не нужно полагаться на полиморфизм с * 1021).*).Однако это кажется довольно слабой причиной, особенно когда std::make_unique не позволяет указывать удалитель, в то время как конструктор std::unique_ptr делает.

И, чтобы было ясно, я не защищаю ввыступает за удаление std::make_unique из стандартной библиотеки (сохранение его имеет смысл, по крайней мере, для обратной совместимости), но скорее задается вопросом, существуют ли еще ситуации, в которых настоятельно рекомендуется std::unique_ptr

Ответы [ 5 ]

0 голосов
/ 13 августа 2019

С тех пор C ++ 17 уточнил порядок оценки, сделав синтаксис A также безопасным

Это действительно недостаточно хорошо.Использование недавно введенного технического условия в качестве гарантии безопасности не является очень надежной практикой:

  • Кто-то может скомпилировать этот код в C ++ 14.
  • Вы бы поощрилииспользование raw new в другом месте, например, путем вставки копии вашего примера.
  • Как предполагает SM, поскольку существует дублирование кода, один тип может быть изменен без изменения другого.
  • Какой-то автоматический рефакторинг в IDE может переместить это new в другое место (хорошо, предоставлено, не так много шансов на это).

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

(это по сути тот же аргумент, который я привел здесь опорядок уничтожения кортежей.)

0 голосов
/ 20 декабря 2018

make_unique отличает T от T[], а T[N], unique_ptr(new ...) - нет.

Вы можете легко получить неопределенное поведение, передав указатель, который был new[] ed для unique_ptr<T>, или передав указатель, который был new ed, для unique_ptr<T[]>.

0 голосов
/ 20 декабря 2018

Вы правы, что основная причина была устранена.Все еще не использует новые правила и что это меньше причин для ввода (не нужно повторять тип или использовать слово new).По общему признанию, это не сильные аргументы, но я действительно не хочу видеть в своем коде new.

Также не забывайте о последовательности.Вы обязательно должны использовать make_shared, поэтому использование make_unique естественно и соответствует шаблону.Затем тривиально изменить std::make_unique<MyClass>(param) на std::make_shared<MyClass>(param) (или наоборот), когда синтаксис А требует гораздо больше переписывания.

0 голосов
/ 20 декабря 2018

Каждое использование new должно быть особенно тщательно проверено на предмет корректности на всю жизнь;это удаляется?Только один раз?

Каждое использование make_unique не для этих дополнительных характеристик;до тех пор, пока объект-владелец имеет «правильное» время жизни, он рекурсивно заставляет уникальный указатель иметь «правильный».

Теперь верно, что unique_ptr<Foo>(new Foo()) одинаково во всех отношениях 1 до make_unique<Foo>();это просто требует более простой «grep вашего исходного кода для всех случаев использования new для их аудита».


1 на самом деле ложь в общем случае.Идеальная пересылка не идеальна, {}, инициализация по умолчанию, массивы - все исключения.

0 голосов
/ 20 декабря 2018

Причина в том, чтобы иметь более короткий код без дубликатов.Сравните

f(std::unique_ptr<MyClass>(new MyClass(param)), g());
f(std::make_unique<MyClass>(param), g());

Вы экономите MyClass, new и фигурные скобки.В make стоит всего на один символ больше по сравнению с ptr .

...