43 votes

Différence entre la syntaxe try-catch pour les fonctions

Je suis tombé sur cette syntaxe récemment pour try-catch pour la fonction.

struct A
{
  int a;

  A (int i) : a(i)  // normal syntax
  {
    try {}
    catch(...) {}
  }

  A ()   // something different
  try : a(0) {}
  catch(...) {}

  void foo ()  // normal function
  try {}
  catch(...) {}
};

Les deux sites la syntaxe est valide . Y a-t-il une différence technique entre ces syntaxes en dehors du style de codage ? L'une des syntaxes est-elle supérieure à l'autre par un quelconque aspect ?

45voto

Alok Save Points 115848

La première syntaxe :
La portée du bloc d'essai commence après l'achèvement de la liste d'initialisation des membres, donc toute exception levée pendant l'initialisation des membres. ne sera pas capturés par ce bloc try-catch.

La deuxième syntaxe :
Cela permet de s'assurer que si une exception est levée pendant la liste d'initialisation des membres, vous êtes en mesure de l'attraper.

La troisième syntaxe :
Il garantit que toute exception lancée entre l'accolade de départ du bloc try à l'intérieur du corps de la fonction est attrapée de manière appropriée, ce qui signifie que toute exception provoquée pendant le passage des arguments (si elle peut se produire) ne sera pas attrapée dans ce bloc try-catch.

Donc oui, ils sont nettement différents dans les fonctionnalités qu'ils fournissent.


EDITAR:
Quelques directives à prendre en compte lors de l'utilisation de la deuxième syntaxe (fonction-essai-bloc) dans les constructeurs et les destructeurs :

Conformément à la norme C++,

Si le bloc de capture ne lève pas l'exception (soit en relançant l'exception originale, soit en lançant quelque chose de nouveau), et que le contrôle atteint la fin du bloc de capture d'un constructeur ou d'un destructeur, alors l'exception originale est automatiquement relancée.

En termes simples :
Le code du gestionnaire d'un constructeur ou d'un destructeur de fonction-try-block. MUST terminer en émettant une exception.

Ligne directrice 1 :
Les gestionnaires de blocs de fonctions de construction n'ont qu'un seul but : traduire une exception. (Et peut-être pour faire de la journalisation ou d'autres effets secondaires.) Ils ne sont utiles pour aucun autre but.

Lancer une exception à partir des destructeurs est une mauvaise idée. aquí pour savoir pourquoi.
Ligne directrice 2 :
Les blocs d'essai des fonctions des destructeurs n'ont aucune utilité pratique. Il ne devrait jamais y avoir quelque chose à détecter pour eux, et même s'il y avait quelque chose à détecter à cause d'un code malveillant, le gestionnaire n'est pas très utile pour faire quoi que ce soit à ce sujet car il ne peut pas supprimer l'exception.

Ligne directrice 3 :
Toujours nettoyer l'acquisition de ressources non gérées dans les gestionnaires de bloc d'essai locaux à l'intérieur du corps du constructeur ou du destructeur, jamais dans les gestionnaires de bloc d'essai de fonction du constructeur ou du destructeur.


Pour les fans de Standardese :

Norme C++, clause 15.3, paragraphe 15 :

Si une déclaration de retour apparaît dans un gestionnaire du bloc de tentative de fonction d'un constructeur, le programme est mal formé.

Norme C++, clause 15.3, paragraphe 16 :

L'exception en cours de traitement est rejetée si le contrôle atteint la fin d'un gestionnaire du bloc d'essai de fonction d'un constructeur ou d'un destructeur. Sinon, une fonction revient lorsque le contrôle atteint la fin d'un gestionnaire du bloc d'essai de fonction (6.6.3). S'écouler hors de la fin d'un bloc de tentative de fonction est équivalent à un retour sans valeur ; cela entraîne un comportement indéfini dans une fonction à retour de valeur (6.6.3).


Références :
Jetez un coup d'œil à ceci à lire absolument ressource aquí pour plus de détails et d'explications.

9voto

Gene Bushuyev Points 3819

Blocage des essais de fonction est surtout utile dans les constructeurs, car il n'y a pas d'autre moyen d'attraper les exceptions dans la liste d'initialisation. Dans les destructeurs, il faut faire attention à retourner dans le bloc catch, car l'exception sera automatiquement relancée. (Et dans une bonne conception, les destructeurs ne doivent pas lancer.) Dans les fonctions normales, cette fonctionnalité n'est pas utile. Edit : un vieil mais toujours bon article : http://drdobbs.com/184401316

3voto

Nemo Points 32838

Autant citer la spécification... Ou au moins une projet .

Article 15 (4) :

A fonction-essai-bloc associe un handler-seq avec le ctor-initialisateur s'il est présent, et le énoncé composé . Une exception levée pendant l'exécution de la commande énoncé composé ou, pour les constructeurs et les destructeurs, lors de l'initialisation ou de la destruction, respectivement, des sous-objets de la classe, transfère le contrôle à un gestionnaire dans un objet de type fonction-essai-bloc de la même manière qu'une exception levée pendant l'exécution d'une commande bloc d'essai transfère le contrôle à d'autres gestionnaires.

(Ici, le handler-seq est le truc après le catch et le compound-statement est le corps de la fonction).

Ainsi, le "bloc d'essai de fonction" sur un constructeur ou un destructeur attrape les exceptions lancées par les initialisateurs de ctor et par la construction ou la destruction des sous-objets.

Sur une fonction autre qu'un constructeur ou un destructeur, cela revient à simplement envelopper le corps de la fonction. (Enfin, d'après ce que je peux discerner en lisant la spécification).

Une fonctionnalité intéressante et nouvelle pour moi. Merci d'en avoir parlé.

2voto

Adam Mitz Points 4540

L'exemple "quelque chose de différent" place le traitement de la liste d'initialisation dans la portée du bloc try.

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