Насколько я понимаю, 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
over std::unique_ptr
в C ++ 17? Вы можете привести несколько примеров?
На данный момент я могу себе представить только одну причину, по которой он позволяет печатать MyClass
только один раз (при условии, что вам не нужно полагаться на полиморфизм std::unique_ptr<Base>(new Derived(param))
). Однако это кажется довольно слабой причиной, особенно когда std::make_unique
не позволяет указать удалитель, в то время как std::unique_ptr
это делает конструктор.
И, чтобы прояснить, я не выступаю за удаление std::make_unique
из стандартной библиотеки (сохранение этого имеет смысл, по крайней мере, для обратной совместимости), а скорее задаюсь вопросом, есть ли еще ситуации, в которых настоятельно рекомендуетсяstd::unique_ptr
источник
std::unique_ptr
? Это не аргумент противmake_unique
std::make_unique
в первую очередь, я не думаю , что будет достаточной причиной , чтобы добавить его в STL, особенно когда это синтаксис , который менее выразительна , чем с помощью конструктора, не болееОтветы:
Вы правы, что главную причину убрали. По-прежнему существуют правила не использовать новые правила и меньше причин для набора текста (не нужно повторять тип или использовать слово
new
). По общему признанию, это не сильные аргументы, но мне очень нравится не видеть ихnew
в своем коде.Также не забывайте о последовательности. Вам обязательно нужно использовать,
make_shared
чтобы использование былоmake_unique
естественным и соответствовало рисунку. Это тот тривиальным изменениеstd::make_unique<MyClass>(param)
кstd::make_shared<MyClass>(param)
(или наоборот) , где синтаксис требует гораздо больше перезаписи.источник
new
мне нужно остановиться и подумать: как долго этот указатель будет жить? Правильно ли я справился? Если есть исключение, все ли правильно очищено? Я бы не хотел задавать себе эти вопросы и тратить на это свое время, и если я не используюnew
, мне не придется задавать эти вопросы.new
. Разве это не было бы замечательно?std::make_shared
- представьте себе случай , когда выделенный объект большой и есть многоstd::weak_ptr
-s , указывающих на него: было бы лучше , чтобы объект был удален , как только последняя общими указатель уничтожен и живет только с небольшой общей областью.std::make_shared
stackoverflow.com/a/20895705/8414561, когда память, которая использовалась для хранения объекта, не может быть освобождена до тех пор, покаstd::weak_ptr
не исчезнет последний (даже если всеstd::shared_ptr
-s указывают на него (и следовательно, сам объект) уже уничтожены).make_unique
отличаетT
отT[]
иT[N]
,unique_ptr(new ...)
не делает.Вы можете легко получить неопределенное поведение, передав указатель, который был
new[]
изменен вunique_ptr<T>
, или передав указатель, который былnew
изменен вunique_ptr<T[]>
.источник
Причина в том, чтобы код был короче, без дубликатов. Сравнить
f(std::unique_ptr<MyClass>(new MyClass(param)), g()); f(std::make_unique<MyClass>(param), g());
Вы экономите
MyClass
,new
и фигурные скобки. Стоимость make всего на один символ больше, чем у ptr .источник
MyClass
, но мне было интересно, есть ли более веская причина для его использования<MyClass>
деталь в первом варианте.std::unique_ptr
его использования. Это связано с различаяstd::unique_ptr<T>
иstd::unique_ptr<T[]>
Каждое использование
new
должно быть тщательно проверено на соответствие сроку службы; это удаляется? Только однажды?Каждое использование
make_unique
не для этих дополнительных характеристик; пока объект-владелец имеет «правильное» время жизни, он рекурсивно делает уникальный указатель «правильным».Это правда, что
unique_ptr<Foo>(new Foo())
во всех отношениях 1 кmake_unique<Foo>()
; для этого просто требуется более простая команда «grep your source code for all use ofnew
to audit it ».1 на самом деле ложь в общем случае. Идеальная пересылка не идеальна,
{}
инициализация по умолчанию, все массивы - исключения.источник
unique_ptr<Foo>(new Foo)
не совсем идентичноmake_unique<Foo>()
последнему.new Foo()
Но в остальном - да.std::unique_ptr
оно запрещено. Если имеет отношение к различениюstd::unique_ptr<T>
иstd::unique_ptr<T[]>
Этого действительно недостаточно. Полагаться на недавно введенный технический раздел как на гарантию безопасности - не очень надежная практика:
new
другом месте, например, путем копирования вашего примера.new
другое место (хорошо, конечно, шансов на это мало).Как правило, это хорошая идея, чтобы ваш код был подходящим / надежным / четко действительным, не прибегая к разделению на разные языки, поиску незначительных или неясных технических положений в стандарте.
(по сути, это тот же аргумент, который я привел здесь относительно порядка уничтожения кортежей.)
источник
Рассмотрим функцию void (std :: unique_ptr (new A ()), std :: unique_ptr (new B ())) {...}
Предположим, что new A () завершился успешно, но new B () выдает исключение: вы перехватываете его, чтобы возобновить нормальное выполнение вашей программы. К сожалению, стандарт C ++ не требует, чтобы объект A был уничтожен, а его память освобождена: утечка памяти происходит незаметно, и ее невозможно очистить. Обернув A и B в std :: make_uniques, вы уверены, что утечки не произойдет:
void function (std :: make_unique (), std :: make_unique ()) {...} Дело в том, что std :: make_unique и std :: make_unique теперь являются временными объектами, а очистка временных объектов правильно указана в стандарт C ++: их деструкторы будут запущены, и память будет освобождена. Поэтому, если вы можете, всегда предпочитайте выделять объекты с помощью std :: make_unique и std :: make_shared.
источник