Зачем использовать std :: make_unique в С++ 17?

Насколько я понимаю, С++ 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

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

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

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

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

Вы сохраняете MyClass, new и брекеты. Марка стоит только на один символ больше по сравнению с ptr.

Ответ 4

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

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

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


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

Ответ 5

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

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

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

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

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