Исключительная безопасность и make_unique

Просто чтобы уточнить, используя make_unique только добавляет безопасность исключений, когда у вас есть несколько распределений в выражении, а не только одно, правильно? Например

void f(T*);

f(new T);

совершенно безопасен в отношении исключений (в отношении распределений и прочего), в то время как

void f(T*, T*);

f(new T, new T);

не является правильным?

13

Решение

Не только когда у вас есть несколько распределений, но и когда вы можете бросить в разных местах. Учти это:

f(make_unique<T>(), function_that_can_throw());

Против:

f(unique_ptr<T>(new T), function_that_can_throw());

Во втором случае компилятору разрешено вызывать (по порядку):

  • new T
  • function_that_can_throw()
  • unique_ptr<T>(...)

Очевидно, если function_that_can_throw на самом деле бросает, то вы утечки. make_unique предотвращает этот случай.

И, конечно же, второе распределение (как в вашем вопросе) — это особый случай function_that_can_throw(),

Как правило, просто используйте make_unique так что ваш код соответствует. Это всегда правильно (читай: исключение безопасно), когда вам нужно unique_ptrи это не влияет на производительность, поэтому нет никаких причин не использовать его (хотя на самом деле не использование его вводит много ошибок).

23

Другие решения

Я думаю, что вам будет лучше сравнивать вещи на самом деле, используя std::unique_ptr<T>:

void f(std::unique_ptr<T>);

f(std::unique_ptr<T>(new T));
f(std::make_unique<T>());

Ни один из этих вызовов не может просочиться, если возникает исключение. тем не мение

void f(std::unique_ptr<T>, std::unique_ptr<T>);

g(std::unique_ptr<T>(new T), std::unique_ptr<T>(new T));
g(std::make_unique<T>(), std::make_unique<T>());

В этом случае версия использует std::unique_ptr<T> явно может просочиться, если выдается исключение (потому что компилятор может начать оценку new-выражения перед построением любого из временных).

6

Начиная с C ++ 17 проблема безопасности исключений была исправлена ​​перепиской [Expr.call]

Инициализация параметра, включая каждое связанное с ним вычисление значения и побочный эффект, определяется неопределенным образом относительно последовательности любого другого параметра.

Вот неопределенно последовательность означает, что одно упорядочено перед другим, но не указано, которое.

f(unique_ptr<T>(new T), function_that_can_throw());

Может иметь только два возможных порядка исполнения

  1. new T unique_ptr<T>::unique_ptr function_that_can_throw
  2. function_that_can_throw new T unique_ptr<T>::unique_ptr

Что означает, что теперь это безопасно.

5
По вопросам рекламы [email protected]