Общих исключений в C++ обработчик catch макро


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

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

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

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

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

#define CatchAll( msg ) \
    catch( const Poco::Exception &e )   \
    {   \
        try{ LogCritical( Logs.System(), std::string( e.displayText() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch( const std::exception &e )    \
    {   \
        try{LogCritical( Logs.System(), std::string( e.what() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch(...)  \
    {   \
        try{ LogCritical( Logs.System(), std::string( "Exception caught in " __FUNCTION__ ". " ).append( msg ) );}catch(...){assert(0);}    \
    }   

Так что у вас есть. Приведенный выше код вызывается такой...

try{ 
   // statements that can throw
}
CatchAll("*Special extra message about what was attempted in the try block*")

Так вот оно, это волшебство. Это не предназначается, чтобы заменить грамотно закодированный блок специфических обработка исключений, это это предназначается, чтобы быстро поставить скелетное изоляции, которое ранее не существовало, и делать это в сухой, портативный, быстрый и простой в понимании способ.

Ок, ок, макросы-это зло, я знаю, но что еще может быть сделано здесь?

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

/// Catch all generic exceptions and log appropriately.
/// Logger is insulated from throwing, so this is a NO THROW operation.
/// Sets rc (integer parameter) so wrapping function can perform cleanup
/// before returning the error number.
#define CatchAllSetRC( rc, msg )    \
    catch( const Poco::Exception &e )   \
    {   \
        (rc) = -1;  \
        try{ LogCritical( Logs.System(), std::string( e.displayText() ).append( msg ));}catch(...){assert(0);}  \
    }   \
    catch( const std::exception &e )    \
    {   \
        (rc) = -1;  \
        try{ LogCritical( Logs.System(), std::string( e.what() ).append( msg ));}catch(...){ assert(0); }   \
    }   \
    catch(...)  \
    {   \
        (rc) = -1;  \
        try{ LogCritical( Logs.System(), std::string( "Exception caught in " __FUNCTION__ ". " ).append( msg ));}catch(...){ assert(0); }   \
    }   

Эта Расширенная версия вызывается с помощью кода вертолет, чтобы абонент мог вернуть его...

int rc = 0;
try{ 
   // statements that can throw
}
CatchAll(rc, "Extra info to append to logged exception message")


Комментарии
2 ответа

В блоке catch, вы можете повторно сгенерировать исключение. Это может быть сделано в функции:

int rc = 0;
try{
// statements that can throw
}catch(...){
HandleException(rc, "Extra info to append to logged exception message");
}

void HandleException(int rc, std::string msg)
{
try{
throw;
}catch(Poco::Exception &e){
// ...
}catch( const std::exception &e){
// ...
}
}

16
ответ дан 20 мая 2011 в 03:05 Источник Поделиться

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

#include <iostream>

using namespace std;

template<typename P, typename Q, typename Ret>
Ret handle_all( Ret(*fn)(P, Q), P p, Q q) {
try {
Ret ret = fn(p, q);
return ret;
}
catch (...) {
cout << "Unexpected exception" << endl;
}
}

template<typename P, typename Ret>
Ret handle_all(Ret (*fn)(P), P p) {
try {
Ret ret = fn(p);
return ret;
}
catch (...) {
cout << "Unexpected exception" << endl;
}
}

int funky_function(int a, string b) {
cout << "a=" << a << endl;
cout << "b=" << b << endl;

throw "wild exception";
// Throwing strings is stupid, this is just an example...
}

int other_function(int a) {
cout << "single parameter a=" << a << endl;

throw "wild exception";
}

int main (void) {
handle_all(funky_function, 12, string("some string"));
handle_all(other_function, 16);
}

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

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

Редактировать: вот то, что функтор решение будет выглядеть следующим образом:

template<typename P, typename Q, typename Ret>
class handle_all {
public:
handle_all(Ret (*fn)(P, Q)) : fn(fn) { }

Ret operator()(P p, Q q) {
try {
Ret ret = fn(p, q);
return ret;
}
catch (...) {
cout << "Unexpected exception" << endl;
}
}

private:
Ret (*fn) (P, Q);
};

Вы должны назвать это так:

handle_all<int, string,int> runner(funky_function);
runner(12, "some string");

Обратите внимание, что в этом случае, автоматическое построение временной СТД::строка из строкового литерала работает, как ожидалось. Кроме того, это не сильно улучшает.

2
ответ дан 19 мая 2011 в 05:05 Источник Поделиться