2010-08-24 37 views
5

Si j'ai un code comme ce qui suit:Est-ce que le lancer C++ sans argument fonctionnera dans un autre cadre pour renvoyer une exception?

try { 
    doSomething(); 
} catch (...) { 
    noteError(); 
} 

void noteError() { 
    try { 
    throw; 
    } catch (std::exception &err) { 
    std::cerr << "Note known error here: " << err.what(); 
    } catch (...) { 
    std::cerr << "Note unknown error here."; 
    } 
    throw; 
} 

Est-ce que les exceptions sont jetés d'origine des deux endroits à l'intérieur du cadre inférieur de noteError()?

+1

L'essayer et voir? Mon soupçon est qu'il ne compilera même pas mais je déteste les exceptions alors je ne sais pas vraiment. –

+5

@Dash, "essayer et voir" ne donne pas toujours une réponse valide et confiante. Peut-être que c'est un comportement indéfini, et l'essayer prouve simplement que cela fonctionne sur votre machine et nulle part ailleurs. Ou, si cela échoue, c'est peut-être dû à un bogue du compilateur qui n'a pas réussi à implémenter cet aspect particulier de la norme. –

+0

@Rob bon point, merci. "Essayez-le et voyez sur chaque compilateur que vous pouvez trouver, puis ajoutez le compilateur en ligne de Comeau à l'avant de cette liste"? :) –

Répondre

4

Le libellé de la norme (§ 15.1/2) est (Souligné par):

Quand une exception est levée, le contrôle est transféré au gestionnaire le plus proche avec un type correspondant (15,3); "Plus proche" désigne le gestionnaire pour lequel l'instruction composée, l'initialisateur ctor ou le corps de fonction suivant le mot clé try a été entré le plus récemment par le fil de contrôle et n'est pas encore sorti.

Quand un bloc try est-il "sorti"? Selon la grammaire (§15/1), essayez les blocs se terminent par séquence de gestionnaires, de sorte que le bloc se termine lorsque le dernier gestionnaire se termine. En d'autres termes:

try // <- start of try block 
{ 
} 
catch (whatever) // <- first handler 
{ 
} 
// ... more handlers 
catch (whatever_again) // <- last handler 
{ 
} // <- end of try block 

Alors oui, votre code est correct. Lorsqu'il est relancé, le bloc try le plus proche a un gestionnaire correspondant (à savoir catch (...)), de sorte que le gestionnaire est entré.

+0

J'ai étendu la question d'une façon que je pense toujours fonctionne, mais pourriez-vous s'il vous plaît confirmer qu'un second lancer fonctionnera également. – WilliamKF

+1

@William: Dès que vous mettez un point-virgule après 'throw'. :) [Cette question] (http://stackoverflow.com/questions/2474429/does-throw-inside-a-catch-ellipsis-rethrow-the-original-error/2474436#2474436) pourrait être intéressante. – GManNickG

+0

Oups, point-virgule ajouté maintenant. – WilliamKF

6

Votre code d'origine était correct. Vous avez pris différents types d'exception et appelé une fonction qui consignerait un message et le relancerait. L'instruction throw n'est pas requise pour apparaître directement à l'intérieur du bloc catch correspondant. Si vous appelez l'une de ces fonctions "note" et que vous êtes pas en train de gérer une exception, votre programme appellera terminate().

Votre nouveau code est également bon. C'est OK pour tout attraper et ensuite appeler une autre fonction qui réitère pour aller à un gestionnaire plus spécifique. C'est the exception dispatcher idiom described in the C++ FAQ. Le bloc de répartition est terminé, mais si la même instruction throw était survenue après noteError retourné (à l'intérieur du bloc original catch) au lieu de l'endroit où il se trouve maintenant, il serait parfaitement ordinaire; c'est démontré dans la norme, §15.1/6.

+0

+1 pour la perspective 'terminer' – Chubsdad