c++ language-lawyer c++17 make-shared exception-safety

std:: make_shared() cambio en C++ 17



language-lawyer c++17 (2)

El documento P0145R3 (que fue aceptado en C ++ 17) refina el orden de evaluación de varias construcciones de C ++, incluyendo

Las expresiones postfix se evalúan de izquierda a derecha. Esto incluye funciones de llamadas y expresiones de selección de miembros.

Específicamente, el documento agrega el siguiente texto al párrafo 5.2.2 / 4 de la norma:

La expresión-postfix se secuencia antes de cada expresión en la lista de expresiones y cualquier argumento predeterminado. Cada cálculo de valor y efecto secundario asociado con la inicialización de un parámetro, y la inicialización en sí, se secuencia antes de cada cálculo de valor y efecto secundario asociado con la inicialización de cualquier parámetro posterior.

En cppref , lo siguiente se mantiene hasta C ++ 17:

código como f(std::shared_ptr<int>(new int(42)), g()) puede causar una pérdida de memoria si se llama a g después de un new int(42) y lanza una excepción, mientras que f(std::make_shared<int>(42), g()) es seguro, ya que dos llamadas de función nunca se entrelazan.

Me pregunto qué cambio introducido en C ++ 17 hace que esto ya no sea aplicable.


El orden de evaluación de los argumentos de función se cambia por P0400R0 .

Antes del cambio, la evaluación de los argumentos de la función no está relacionada entre sí. Esto significa que la evaluación de g() se puede insertar en la evaluación de std::shared_ptr<int>(new int(42)) , que causa la situación descrita en su contexto citado.

Después del cambio, la evaluación de los argumentos de la función se secuencia en forma indeterminada sin intercalado, lo que significa que todos los efectos secundarios de std::shared_ptr<int>(new int(42)) tienen lugar antes o después de los de g() . Ahora considere el caso donde g() puede lanzar.

  • Si todos los efectos secundarios de std::shared_ptr<int>(new int(42)) tienen lugar antes que los de g() , la memoria asignada será desasignada por el destructor de std::shared_ptr<int> .

  • Si todos los efectos secundarios de std::shared_ptr<int>(new int(42)) tienen lugar después de los de g() , incluso no hay asignación de memoria.

En cualquier caso, no hay pérdida de memoria de nuevo de todos modos.