C ++, __try e try / catch / finally

Eu estou querendo saber um pouco sobre C + + try / catch / finally bloqueia. Eu vi esses comandos com dois sublinhados como __try. Mas os projetos do MVSC 2010 também são executados sem os sublinhados. Então, quando você precisa desses sublinhados?

No Windows, as exceções são suportadas no nível do sistema operacional. Chamado Structured Exception Handling (SEH), eles são o equivalente aproximado aos sinais Unix. Compiladores que geram código para o Windows geralmente aproveitam isso, eles usam a infraestrutura SEH para implementar exceções do C ++.

De acordo com o padrão C ++, as palavras-chave throw e catch apenas lançam e capturam exceções do C ++. O código de exceção SEH correspondente para o compilador MSVC é 0xe06d7343. Os últimos 3 bytes são o código ASCII para “msc”.

Unificá-lo com o suporte ao sistema operacional também significa que os destruidores de C ++ serão chamados durante o desenrolar da pilha para uma exceção SEH. O código que faz o desenrolamento está dentro do Windows e trata o SEH gerado por um lance exatamente da mesma maneira que qualquer SEH. No entanto, o compilador da Microsoft tem uma otimização que tenta evitar a geração do código necessário que garante que os destruidores sejam chamados em todos os casos. Se puder provar que não há nenhuma instrução throw dentro do bloco de escopo que controla a vida útil do object, ele pula o código de registro. Isso não é compatível com exceções assíncronas do SEH, você deve usar a opção de compilation / EHa para suprimir essa otimização se você pretende capturar exceções SEH.

Existem muitos tipos de exceção SEH. Os que podem ser gerados pelo sistema operacional são listados no arquivo de header ntstatus.h SDK. Além disso, você pode interoperar com o código que usa o SEH para implementar seu próprio tratamento de exceção, eles usarão seu próprio código de exceção. Como no .NET, as exceções gerenciadas usam o código de exceção 0xe0434f4d (“com”).

Para capturar exceções SEH em um programa C ++, você deve usar a palavra-chave __try não-padrão. A palavra-chave __except é análoga à palavra-chave catch do C ++. Ele tem mais resources, você especifica uma expressão de filtro de exceção que determina se uma exceção ativa deve ou não ser capturada. Tudo é possível, mas você normalmente só observa as informações de exceção transmitidas para ver se está interessado em lidar com elas. A palavra-chave __finally permite escrever um código que é executado após a manipulação da exceção. Não equivalente para isso em C ++, mas não é incomum em outros idiomas.

Tudo isso é bastante mal documentado, como apontado nos comentários. A prova está no pudim. Aqui está um programa de exemplo que você pode jogar. Ele demonstra como as exceções SEH ainda permitem que os destruidores de C ++ sejam chamados, desde que você compile com / EHa e como as exceções de C ++ são implementadas sobre o SEH. Compilador MSVC necessário, execute com Ctrl + F5 para evitar que o depurador seja útil:

 #include "stdafx.h" #include  #include  // 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; } 

Saída:

 Filtering c0000005 destructed caught Filtering e06d7363 destructed caught 

__try / __except é para capturar SEH (erros gerados pelo Windows) não para capturar exceções gerais.

try / catch é o que o padrão C ++ especifica para manipular exceções gerais do C ++.

Para o código C ++ padrão que você escreve, você deve sempre usar try / catch e não __try / __except

Além disso, finally não é a construção especificada pelo C ++ Standard. Ela funciona para você porque é uma extensão de compilador da Microsoft .

__try/__except é específico da Microsoft Se você quiser que seu código seja compilável com outros compiladores (por exemplo, g ++) (ou) em outro sistema operacional, evite usá-los e siga as instruções padrão try/catch