Зачем использовать 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 в другое место (хорошо, конечно, шансов на это немного).
Как правило, было бы неплохо, чтобы ваш код был соответствующим/надежным/четко действующим, не прибегая к языковой иерархии, не обращая внимания на незначительные или неясные технические положения в стандарте.
(По сути, это тот же аргумент, который я привел здесь о порядке уничтожения кортежей.)