std :: make_shared() изменение в С++ 17
В cppref выполняется следующее действие до С++ 17:
код, такой как f(std::shared_ptr<int>(new int(42)), g())
может вызвать утечку памяти, если g
вызывается после new int(42)
и генерирует исключение, тогда как f(std::make_shared<int>(42), g())
безопасен, поскольку два вызова функций никогда не чередуются.
Мне интересно, какое изменение, внесенное в С++ 17, делает это более неприменимым.
Ответы
Ответ 1
Порядок оценки аргументов функции изменяется на P0400R0.
Перед изменением оценка аргументов функции не зависит от друг друга. Это означает, что оценка g()
может быть вставлена в оценку std::shared_ptr<int>(new int(42))
, что приводит к ситуации, описанной в вашем цитированном контексте.
После изменения оценка аргументов функции неопределенно секвенирована без перемежения, что означает, что все побочные эффекты std::shared_ptr<int>(new int(42))
имеют место либо до, либо после g()
. Теперь рассмотрим случай, когда g()
может бросать.
-
Если все побочные эффекты std::shared_ptr<int>(new int(42))
имеют место перед символами g()
, выделенная память будет освобождена деструктором std::shared_ptr<int>
.
-
Если все побочные эффекты std::shared_ptr<int>(new int(42))
происходит после тех, что у g()
, выделения памяти даже нет.
В любом случае утечки памяти еще нет.
Ответ 2
В документе P0145R3 (который был принят в C++ 17) уточняется порядок оценки нескольких конструкций C++, в том числе
Постфиксные выражения оцениваются слева направо. Сюда входят вызовы функций и выражения выбора членов
В частности, документ добавляет следующий текст к пункту 5.2.2/4 стандарта:
Постфикс-выражение секвенируется перед каждым выражением в списке выражений и любым аргументом по умолчанию. Каждое вычисление значения и побочный эффект, связанные с инициализацией параметра и самой инициализацией, секвенируются перед каждым вычислением значения и побочным эффектом, связанным с инициализацией любого последующего параметра.