смешивание обработки исключений c ++ и SEH (windows) - PullRequest
5 голосов
/ 15 июля 2011

У меня есть функция, в которой я вызываю getaddrinfo(), чтобы получить sockaddr*, которая предназначена для памяти, выделяемой системой.Как многие могут знать, вам нужно вызвать freeaddrinfo(), чтобы освободить память, выделенную getaddrinfo ().

Теперь в моей функции есть несколько мест, где я могу выбросить исключение, потому что некоторая функцияне удалось.Моим первым решением было включить freeaddrinfo() в каждый блок if.Но для меня это выглядело уродливо, потому что мне пришлось бы в любом случае вызывать его до того, как моя функция вернулась, поэтому я придумал попытку-наконец-то в SEH ...

Но проблема, с которой я столкнулся, заключается в том, чтоне разрешается кодировать операторы throw в __try-block

Затем я читал на msdn и пытался поменять операторы throw в вспомогательную функцию, вызываемую из __try-block ...и вуаля, компилятор больше не стонал ...

Почему это так?И это безопасно?Это не имеет смысла для меня: /

Код:

void function()
{
    //...
    addrinfo* pFinal;
    __try
    {
        getaddrinfo(..., &pFinal);

        //if(DoSomething1() == FAILED)
        //  throw(exception);           //error C2712: Cannot use __try in functions that require object unwinding

        //but this works
        Helper();


        //...

    }
    __finally
    {
        freeaddrinfo();
    }
}


void Helper()
{
    throw(Exception);
}

РЕДАКТИРОВАТЬ:

попробовал следующее, и это работает с бросанием целого числа, но не когда яиспользуйте класс в качестве исключения:

class X
{
public:
    X(){};
    ~X(){};
};


void Helper()
{
    throw(X());
}


void base()
{
    __try
        {
            std::cout << "entering __try\n";

            Helper();

            std::cout << "leaving __try\n";
        }
        __finally
        {
            std::cout << "in __finally\n";
        }
};


int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        base();
    }
    catch(int& X)
    {
        std::cout << "caught a X" << std::endl;
    }

    std::cin.get();
    return 0;
}

Почему?: /

Ответы [ 3 ]

9 голосов
/ 15 июля 2011

Вы не можете смешивать два типа исключений. Под прикрытием исключения C ++ используют SEH, и ваш обработчик исключений SEH может испортить логику распространения исключений. В результате компилятор C ++ не позволит вам смешивать их.

PS: Структурная обработка исключений почти всегда является ОЧЕНЬ плохой идеей. Внутренне Microsoft запретила использование SEH, за исключением очень ограниченных обстоятельств. Любой компонент, который использует структурированную обработку исключений, автоматически подвергается интенсивным проверкам кода (у нас есть инструменты, которые сканируют код в поисках его использования, чтобы убедиться, что ни одно из случаев не пропущено).

Проблема с SEH заключается в том, что при использовании SEH очень легко случайно ввести уязвимости безопасности.

3 голосов
/ 15 июля 2011

Вы можете заключить addrinfo в класс, который вызывает getaddrinfo в конструкторе и freeaddrinfo в его деструкторе.

Таким образом, он всегда будет освобожден, вне зависимости от того, было ли выброшено исключение или нет.

0 голосов
/ 16 июля 2011
catch(int& X)
{
    std::cout << "caught a X" << std::endl;
}

Это не ловит X, оно ловит int&. Поскольку нет соответствующего блока catch, исключение не выполняется, разматывание стека не происходит, и обработчики __finally не запускаются.

Вы можете поместить catch (...) в точку входа вашего потока (которая составляет main() для основного потока), чтобы гарантировать, что разматывание стека происходит, хотя некоторые исключения не могут быть восстановлены, что не относится к исключению C ++.

...