56 votes

C++, __try et try/catch/finally

Je m'interroge un peu sur les blocs C++ try/catch/finally. J'ai vu ces commandes avec deux underscores comme __try. Mais les projets MVSC 2010 fonctionnent également sans les underscores. Quand avez-vous besoin de ces caractères de soulignement ?

104voto

Hans Passant Points 475940

Sous Windows, les exceptions sont prises en charge au niveau du système d'exploitation. Appelées Structured Exception Handling (SEH), elles sont l'équivalent approximatif des signaux Unix. Les compilateurs qui génèrent du code pour Windows en profitent généralement, ils utilisent l'infrastructure SEH pour implémenter les exceptions C++.

Conformément à la norme C++, le lancez y attraper Les mots clés ne font que lancer et attraper des exceptions C++. Le code d'exception SEH correspondant pour le compilateur MSVC est 0xe06d7363. Les 3 derniers octets sont le code ASCII de "msc".

L'unifier avec le support du système d'exploitation signifie également que les destructeurs C++ seront appelés pendant le déroulement de la pile pour une exception SEH. Le code qui effectue le déroulement de la pile se trouve dans Windows et traite l'exception SEH soulevée par une exception de type lancez de la même manière que n'importe quel SEH. Cependant, le compilateur Microsoft possède une optimisation qui tente d'éviter de générer le code nécessaire pour garantir que les destructeurs sont appelés dans tous les cas. S'il peut prouver qu'il n'y a pas d'instruction throw à l'intérieur du bloc scope qui contrôle la durée de vie de l'objet, il saute le code d'enregistrement. Ceci n'est pas compatible avec les exceptions SEH asynchrones, vous devriez utiliser l'option de compilation /EHa pour supprimer cette optimisation si vous avez l'intention de capturer des exceptions SEH.

Il existe de nombreux types d'exceptions SEH. Celles qui peuvent être générées par le système d'exploitation sont répertoriées dans le fichier d'en-tête ntstatus.h du SDK. De plus, vous pouvez interopérer avec du code qui utilise SEH pour implémenter sa propre gestion des exceptions, il utilisera son propre code d'exception. Comme pour .NET, les exceptions gérées utilisent le code d'exception 0xe0434f4d ("com").

Pour attraper les exceptions SEH dans un programme C++, vous devez utiliser le mot-clé non standard __try. Le mot-clé __except est analogue au mot-clé C++ attraper mot-clé. Il a plus de possibilités, vous spécifiez une expression de filtre d'exception qui détermine si une exception active doit être attrapée ou non. Tout est possible, mais vous ne regardez généralement que les informations relatives aux exceptions transmises pour savoir si vous souhaitez les traiter. Le mot-clé __finally vous permet d'écrire du code qui s'exécute après le traitement de l'exception. Il n'y a pas d'équivalent pour cela en C++ mais ce n'est pas rare dans d'autres langages.

Tout cela est assez mal documenté comme le soulignent les commentaires. La preuve est dans le pudding. Voici un exemple de programme avec lequel vous pouvez jouer. Il démontre comment les exceptions SEH permettent toujours d'appeler les destructeurs C++, à condition de compiler avec /EHa et comment les exceptions C++ sont implémentées au-dessus de SEH. Compilateur MSVC requis, exécuté avec Ctrl+F5 pour éviter que le débogueur ne soit utile :

#include "stdafx.h"
#include <windows.h>
#include <iostream>

// NOTE: the value of the C/C++, Code Generation, Enable C++ Exceptions setting in important
// Try it both with /EHsc (the default) and /EHa to see the difference

class Example {  
public:
    ~Example() { std::cout << "destructed" << std::endl; }
};

int filterException(int code, PEXCEPTION_POINTERS ex) {
    std::cout << "Filtering " << std::hex << code << std::endl;
    return EXCEPTION_EXECUTE_HANDLER;
}

void testProcessorFault() {
    Example e;
    int* p = 0;
    *p = 42;
}

void testCppException() {
    Example e;
    throw 42;
}

int main()
{
    __try {
        testProcessorFault();
    }
    __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
        std::cout << "caught" << std::endl;
    }
    __try {
        testCppException();
    }
    __except(filterException(GetExceptionCode(), GetExceptionInformation())) {
        std::cout << "caught" << std::endl;
    }
    return 0;
}

Sortie :

Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught

27voto

Alok Save Points 115848

__try / __except est pour attraper SEH (erreurs générées par Windows) pas pour attraper les exceptions générales.

try / catch est ce que la norme C++ spécifie pour la gestion des exceptions générales C++.

Pour le code C++ standard que vous écrivez, vous devriez toujours utiliser try / catch et non __try / __except

Aussi, finally n'est pas une construction spécifiée par la norme C++, elle fonctionne pour vous car c'est une Extension du compilateur Microsoft .

3voto

Ioan Paul Pirau Points 1502

__try/__except est spécifique à Microsoft Si vous voulez que votre code soit compilable avec d'autres compilateurs (par exemplec g++) (ou) dans un autre système d'exploitation, évitez de les utiliser, et tenez-vous-en à l'option standard try/catch déclarations

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