35 votes

Quel est l'ordre de destruction des arguments de la fonction ?

Si une fonction f avec des paramètres p_1 , ..., p_n de types T_1 , ..., T_n est appelé respectivement avec les arguments a_1 , ..., a_n et que son corps lève une exception, se termine ou revient, dans quel ordre les arguments sont-ils détruits et pourquoi ? Veuillez fournir une référence à la norme, si possible.

EDITAR: En fait, je voulais poser une question sur les "paramètres" de la fonction, mais comme T.C. et Columbo ont réussi à dissiper ma confusion, je laisse cette question sur les arguments et je pose la question suivante une nouvelle question distincte sur les paramètres . Voir les commentaires sur cette question pour la distinction.

21voto

Zereges Points 3599

Je n'ai pas réussi à trouver la réponse dans la norme, mais j'ai pu tester cela sur 3 compilateurs C++ compliants les plus populaires. La réponse de R Sahu explique à peu près qu'il s'agit d'une mise en œuvre définie.

§5.2.2/8 : Les évaluations de l'expression postfixe et des arguments sont toutes non séquencées les unes par rapport aux autres. l'un par rapport à l'autre. Tous les effets secondaires des évaluations des arguments sont séquencés avant l'entrée de la fonction.

Compilateur Visual Studio C++ (Windows) et gcc (Debian)
Les arguments sont construits dans l'ordre inverse de leur déclaration et détruits dans l'ordre inverse (donc détruits dans l'ordre de délcaration) :

2
1
-1
-2

Clang (FreeBSD)
Les arguments sont construits dans l'ordre de leur déclaration et détruits dans l'ordre inverse :

1
2
-2
-1

Tous les compilateurs ont reçu l'instruction de traiter le code source comme du C++11 et j'ai utilisé l'extrait suivant pour démontrer la situation :

struct A
{
    A(int) { std::cout << "1" << std::endl; }
    ~A() { std::cout << "-1" << std::endl; }
};

struct B
{
    B(double) { std::cout << "2" << std::endl; }
    ~B() { std::cout << "-2" << std::endl; }
};

void f(A, B) { }

int main()
{
    f(4, 5.);
}

14voto

6502 Points 42700

Dans le §5.2.2 [4] N3337 est assez explicite sur ce qui se passe ( projet en ligne ):

Lors de l'initialisation d'un paramètre, une implémentation peut éviter la construction de temporaires supplémentaires en combinant les conversions sur l'argument associé et/ou la construction de temporaires avec l'initialisation du para. l'initialisation du paramètre (voir 12.2). La durée de vie d'un paramètre se termine lorsque la fonction dans laquelle il est défini revient.

Ainsi, par exemple, dans

f(g(h()));

la valeur de retour de l'appel h() est un temporaire qui sera détruit à la fin de l'expression complète. Cependant, le compilateur peut éviter ce temporaire et initialiser directement avec sa valeur le paramètre de l'expression complète. g() . Dans ce cas la valeur de retour sera détruite une fois que g() retourne (c'est-à-dire AVANT d'appeler f() ).

Si j'ai bien compris ce qui est indiqué dans la norme, il n'est toutefois pas permis d'avoir la valeur renvoyée par la fonction h() pour survivre jusqu'à la fin de l'expression complète, à moins qu'une copie ne soit faite (le paramètre) et que cette copie ne soit détruite qu'une fois g() retours.

Les deux scénarios sont les suivants :

  1. h La valeur de retour est utilisée pour initialiser directement g paramètre. Cet objet est détruit lorsque g et avant d'appeler f .
  2. h La valeur de retour est une valeur temporaire. Une copie est faite pour initialiser g et il est détruit lorsque g retours. Le temporaire original est détruit à la fin de l'expression complète à la place.

Je ne sais pas si les implémentations suivent les règles en la matière.

11voto

R Sahu Points 24027

L'ordre dans lequel les arguments d'une fonction sont évalués n'est pas spécifié par la norme. Extrait de la norme C++11 ( projet en ligne ):

5.2.2 Appel de fonction

8 [ Note : Les évaluations de l'expression postfixe et des expressions arguments sont toutes non séquencées les unes par rapport aux autres. Tous les effets secondaires des évaluations des expressions arguments sont séquencés avant que la fonction soit entrée (voir 1.9). -note finale ]

Par conséquent, c'est à l'implémentation de décider dans quel ordre évaluer les arguments d'une fonction. Ceci, à son tour, implique que l'ordre de construction des arguments dépend également de l'implémentation.

Une mise en œuvre judicieuse détruirait les objets dans l'ordre inverse de leur construction.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X