web-dev-qa-db-fra.com

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

Dans cppref , ce qui suit tient jusqu'à C++ 17:

du code tel que f(std::shared_ptr<int>(new int(42)), g()) peut provoquer une fuite de mémoire si g est appelé après new int(42) et lève une exception, tandis que f(std::make_shared<int>(42), g()) est sûr, car deux les appels de fonction ne sont jamais entrelacés.

Je me demande quel changement introduit dans C++ 17 rend cela non applicable.

27
Lingxi

L'ordre d'évaluation des arguments de fonction est modifié par P0400R .

Avant la modification, l'évaluation des arguments de fonction n'est pas séquencée les uns par rapport aux autres. Cela signifie que l'évaluation de g() peut être insérée dans l'évaluation de std::shared_ptr<int>(new int(42)), ce qui provoque la situation décrite dans votre contexte cité.

Après le changement, l'évaluation des arguments de fonction est séquencée de façon indéterminée sans entrelacement, ce qui signifie que tous les effets secondaires de std::shared_ptr<int>(new int(42)) ont lieu avant ou après ceux de g(). Considérons maintenant le cas où g() peut lancer.

  • Si tous les effets secondaires de std::shared_ptr<int>(new int(42)) se produisent avant ceux de g(), la mémoire allouée sera désallouée par le destructeur de std::shared_ptr<int>.

  • Si tous les effets secondaires de std::shared_ptr<int>(new int(42)) se produisent après ceux de g(), il n'y a même pas d'allocation de mémoire.

Dans les deux cas, il n'y a de toute façon plus de fuite de mémoire.

17
xskxzr

Le papier P0145R (qui a été accepté en C++ 17) affine l'ordre d'évaluation de plusieurs constructions C++, y compris

Les expressions de suffixe sont évaluées de gauche à droite. Cela inclut les appels de fonctions et les expressions de sélection de membres

Plus précisément, le document ajoute le texte suivant au paragraphe 5.2.2/4 de la norme:

L'expression postfixe est séquencée avant chaque expression dans la liste d'expressions et tout argument par défaut. Chaque calcul de valeur et effet secondaire associé à l'initialisation d'un paramètre, et l'initialisation elle-même, est séquencé avant chaque calcul de valeur et effet secondaire associé à l'initialisation de tout paramètre ultérieur.

20
lisyarus