Преимущества использования std :: make_unique для нового оператора

Каковы преимущества использования std::make_unique над new оператором для инициализации std::unique_ptr?

Другими словами, почему

std::unique_ptr<SomeObject> a = std::make_unique(SomeObject(...))

лучше, чем делать

std::unique_ptr<SomeObject> a = new SomeObject(...)

Я попытался найти много онлайн, и я знаю, что это хорошее правило, чтобы избежать new оператора в современном C++, но я не уверен, какие преимущества в этом точном сценарии. Предотвращает ли это утечку памяти, которая может произойти? std::make_unique ли делать std::make_unique чем использовать new?

Ответ 1

преимущества

  • make_unique учит пользователей "никогда не говорить new/delete и new[]/delete[] " без оговорок.

  • make_unique два преимущества с make_shared (исключая третье преимущество, повышенную эффективность). Во-первых, unique_ptr<LongTypeName> up(new LongTypeName(args)) должно упоминать LongTypeName дважды, в то время как auto up = make_unique<LongTypeName>(args) упоминает его один раз.

  • make_unique предотвращает make_unique неуказанного порядка оценки, вызванную выражениями типа foo(unique_ptr<X>(new X), unique_ptr<Y>(new Y)). (Следуя совету "никогда не говорить new ", это проще, чем "никогда не говорить ничего new, если только вы не сразу отдадите его на имя unique_ptr ").

  • make_unique тщательно внедряется для обеспечения безопасности исключений и рекомендуется для прямого вызова конструкторов unique_ptr.

Когда не используется make_unique

  • Не используйте make_unique если вам нужен пользовательский отладчик или вы используете необработанный указатель из другого места.

источники

  1. Предложение std::make_unique.
  2. Herb Sutter GotW # 89 Решение: Умные указатели

Ответ 2

Разница в том, что std::make_unique возвращает объект типа std::unique_ptr а new возвращает указатель на созданный объект. При сбоях в распределении памяти они будут бросать. Держись, это не так просто. Читайте дальше.

Рассмотрим такую функцию ниже:

void func(ClassA* a, ClassB* b){
     ......
}

Когда вы делаете вызов как func(new A(), new B()); Компилятор может выбрать оценку аргументов функции слева направо или в любом порядке, который он пожелает. Пусть предполагаемая оценка слева направо: что происходит, когда первое new выражение успешно выполняется, но второе new выражение бросает?

Настоящая опасность здесь заключается в том, когда вы поймаете такое исключение; Да, вы могли поймать исключение, вызванное new B(), и возобновить нормальное выполнение, но new A() уже преуспел, и его память будет пропущена. Никто не убирает его... * рыдает...

Но с make_unique вас не может быть утечки, потому что произойдет make_unique стека (и деструктор ранее созданного объекта будет запущен). Следовательно, предпочтение make_unique будет ограничивать вас безопасностью исключений. В этом случае std::make_unique предоставляет "Базовую безопасность исключения", которую выделенная память и объект, созданные new, никогда не будут потеряны, несмотря ни на что. Даже до конца времени... :-)

Вы должны прочитать Herb Sutter GoTW102