Повторное использование кода в обработке исключений - PullRequest
15 голосов
/ 11 мая 2009

Я разрабатываю C api для некоторой функциональности, написанной на C ++, и хочу убедиться, что никакие исключения не распространяются ни в одну из экспортируемых функций C.

Простой способ сделать это - убедиться, что каждая экспортируемая функция содержится в:

try {
   // Do the actual code
} catch (...) {
   return ERROR_UNHANDLED_EXCEPTION;
}

Допустим, я знаю, что одно исключение, которое часто пропускается в коде C ++, это std :: bad_alloc, и я хочу обработать его специально, вместо этого я бы написал что-то вроде этого:

try {
   // Run the actual code
} catch (std::bad_alloc& e) {
   return ERROR_BAD_ALLOC;
} catch (...) {
   return ERROR_UNHANDLED_EXCEPTION;
}

Можно ли разобрать это каким-то умным способом, чтобы я мог глобально обрабатывать некоторые ошибки по-разному, не добавляя новый оператор catch для обработчика исключений вокруг каждой экспортируемой функции?

Я знаю, что это можно решить с помощью препроцессора, но прежде чем идти по этому пути, я бы убедился, что другого способа сделать это не существует.

Ответы [ 6 ]

28 голосов
/ 11 мая 2009

Вы можете использовать только одну функцию-обработчик для всех возможных исключений и вызывать ее из каждой или из ваших функций реализации API, как показано ниже:

int HandleException()
{
    try 
    {
        throw;
    }

    // TODO: add more types of exceptions

    catch( std::bad_alloc & ) 
    {
       return ERROR_BAD_ALLOC;
    }
    catch( ... )
    {
        return ERROR_UNHANDLED_EXCEPTION;
    }
}

И в каждой экспортируемой функции:

try
{
    ...
}
catch( ... )
{
    return HandleException();
}
4 голосов
/ 11 мая 2009

Хороший ответ уже есть. Но только FYI, его называют «диспетчер исключений», см. C ++ FAQ .

1 голос
/ 11 мая 2009

Джем ответ немного проще, чем это решение. Но использование макроса препроцессора можно заменить на использование шаблонов. Примерно так (больше доработок вы могли бы сделать):

template <class T, void (T::*FUNC)()>
class CatchWrapper
{
public:

    static void WrapCall(T* instance)
    {
        try
        {
            (instance->*FUNC)();
        }
        catch (std::bad_alloc&)
        {
            // Do Something 1
        }
        catch (std::exception& e)
        {
            // Do Something 2
        }
        catch (...)
        {
            // Do Something 3
        }
    }
};


class Foo
{
public:
    void SomeCall()
    {
        std::cout << "Do Something" << std::endl;
    }
};


int main(int argc, char* argv[])
{
    Foo i;
    CatchWrapper<Foo, &Foo::SomeCall>::WrapCall(&i);
    return 0;
}
1 голос
/ 11 мая 2009

А как же:

try{
    //Your code here
} catch(std::exception e)
{
   return translateExceptionToErrorCode(e);
} catch(...)
{
   return UNKNOWN_EXCEPTION_THROWN;
}
0 голосов
/ 11 мая 2009

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

То, как вы это сделаете, зависит от того, как выглядят ваши классы исключений. Если вы контролируете иерархию классов исключений, вы можете убедиться, что каждый класс предоставляет перевод с использованием виртуального метода. Если нет, вы все равно можете найти практичным использование функции переводчика и тестирование типов полученного исключения 'std :: exception', которое он получает, чтобы преобразовать его в код ошибки, во многом как предполагал Джем (помните: выброшенные исключения повредят производительность в любом случае, так что не беспокойтесь о медленном переводе).

0 голосов
/ 11 мая 2009

Никогда не используйте catch(...), если только вы не планируете более или менее немедленное повторное бросание. Вы наверняка потеряете любую информацию об ошибке, которая могла вам помочь, чтобы выяснить причину ошибки.

Мне нравится ваша вторая схема немного лучше - поймать известный набор исключений, в идеале, потому что они являются единственными, которые выдает ваш код, и позволить остальным - разрешить сбой приложения, возможно, лучшее, что можно сделать с Вы вызвали неизвестное поведение, лучше всего «ответственно падать».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...