Подтвердить что ты не робот

С++, __try и try/catch/наконец

Мне интересно немного о блоках try/catch/finally С++. Я видел эти команды с двумя подчеркиваниями, такими как __try. Но проекты MVSC 2010 также работают без подчеркивания. Итак, когда вам нужны эти подчеркивания?

4b9b3361

Ответ 1

В Windows исключения поддерживаются на уровне операционной системы. Вызывается обработка структурированных исключений (SEH), они являются грубым эквивалентом сигналов Unix. Компиляторы, которые генерируют код для Windows, обычно используют это, они используют инфраструктуру SEH для реализации исключений С++.

В соответствии со стандартом С++ ключевые слова throw и catch только бросают и улавливают исключения С++. Соответствующий код исключения SEH для компилятора MSVC равен 0xe06d7343. Последние 3 байта - это код ASCII для "msc".

Объединение его с поддержкой операционной системы также означает, что деструкторы С++ будут вызваны во время разворачивания стека для исключения SEH. Код, который выполняет разматывание, находится внутри Windows и обрабатывает SEH, поднятый броском точно так же, как любой SEH. Однако у компилятора Microsoft есть оптимизация, которая пытается избежать генерации необходимого кода, который гарантирует, что деструкторы вызываются во всех случаях. Если это может доказать, что в блоке области действия, который управляет временем жизни объекта, не существует инструкции throw, она пропускает регистрационный код. Это несовместимо с асинхронными исключениями SEH, вы должны использовать параметр компиляции /EHa для подавления этой оптимизации, если вы намерены поймать исключения SEH.

Существует много типов исключений SEH. Те, которые могут быть сгенерированы операционной системой, перечислены в файле заголовка ntstatus.h SDK. Кроме того, вы можете взаимодействовать с кодом, который использует SEH для реализации собственной обработки исключений, они будут использовать свой собственный код исключения. Подобно .NET, управляемые исключения используют код исключения 0xe0434f4d ( "com" ).

Чтобы перехватывать исключения SEH в программе на С++, вы должны использовать нестандартное ключевое слово __try. Ключевое слово __except аналогично ключевому слову С++ catch. У него больше возможностей, вы указываете выражение фильтра исключений, которое определяет, следует ли поймать активное исключение. Все возможно, но вы обычно смотрите только на информацию о прошедших исключениях, чтобы узнать, заинтересованы ли вы в ее обработке. Ключевое слово __finally позволяет писать код, который запускается после обработки исключения. Нет эквивалента для этого в С++, но не редкость на других языках.

Все это довольно плохо документировано, как указано в комментариях. Доказательство находится в пудинге. Вот пример программы, с которой вы можете играть. Он демонстрирует, как исключения SEH по-прежнему позволяют вызывать деструкторы С++, если вы компилируете /EHa и как исключения С++ реализованы поверх SEH. Требуется компилятор MSVC, запустите с помощью Ctrl + F5, чтобы избежать использования отладчика:

#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;
}

Вывод:

Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught

Ответ 2

__try/__except предназначен для ловли SEH (ошибки, вызванные Windows) не для обнаружения общих исключений,

try/catch - это то, что указывает стандарт С++ для обработки общих исключений С++.

Для стандартного кода на С++, который вы пишете, вы всегда должны использовать try/catch, а не __try/__except

Кроме того, finally не является стандартной конструкцией С++ Standard, он работает для вас, потому что это расширение компилятора Microsoft.