2015-12-08 2 views
8

В каждой из моих основных функций я хотел бы поймать определенные классы исключений и преобразовать их в коды выхода.Неявная попытка {} catch вокруг main

Есть ли более элегантное решение для этого, чем запуск и завершение каждой основной функции с помощью макросов, которые будут вставлять неявные try {} catch Я хочу?

Могу ли я как-то добиться этого с помощью функции std::set_terminate?

Пример:

int main(){ 
    try { //<- insert this 

    /* 
    the business logic goes here 
    */ 

    //-> and insert this 
    } 
    catch(const Someclass1& e){ return 2; } 
    catch(const Someclass2& e){ return 3; } 
    //... 
    catch(...){ return 1; } 
} 
+3

Все ваши исключения связаны с наследством (или они могут быть?) – quamrana

+0

@quamrana Да. На самом деле это может быть только один виртуальный базовый класс. – PSkocik

+2

Затем вы можете включить каждый класс исключений в код возврата, а один try/catch в 'main()' может извлечь его и вернуть. – quamrana

ответ

6

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

template <typename Callable> 
int call_and_translate_for_boundary(Callable&& func) 
try { 
    func(); 
    return 0; 
} 
catch(const Someclass1& e){ return 2; } 
catch(const Someclass2& e){ return 3; } 
//... 
catch(...){ return 1; } 

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

int main() { 
    return call_and_translate_for_boundary([&]{ 
     //business logic here 
    }); 
} 
0

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

1

Я думаю, вы можете сделать что-то с макросами, если хотите. Вот как это делается:

#define MY_MAIN int main(int argc, char** argv) try // <- yes, try here 
#define MY_CATCH catch (const Someclass1& e){ return 1; } \ 
       catch (const Someclass2& e){ return 1; } \ 
       ... \ 
       catch (...) { return -1; } 

MY_MAIN 
{ 
    // usual business... 
    return 0; 
} 
MY_CATCH 

Идея состоит в том, чтобы позволить макросу написать попытку поймать «вокруг» главного тела функции, что является законным.

int main() try { throw 1; } catch (int i) { return 0; } 

little example live

1

Я обычно делаю это:

int main2(); 

int main() try { 
    return main2(); 
} catch(std::exception &e) 
{ 
    // some display... 
} 

Вы можете иметь больше ловить обработчики конечно.

Если вам нужно разместить тот же список обработчиков улова в нескольких точках входа, это будет другой вопрос. Решение должно содержать catch(...) { foo(); }, где foo() функция try { throw; }, за которой следуют все обработчики захвата.

0

cleanest solution Я знаком с внешностью, как:

void standard_exception_handler(); 

try { 
    whatever(); 
} 
catch (...) 
{ 
    standard_exception_handler(); 
} 

void standard_exception_handler() 
{ 
    try { 
     throw; // a bare throw preserves the original exception information 
    } 
    catch (const std::exception& ex) 
    { 
     ... 
    } 
    catch (const other_exception& ex) 
    { 
     ... 
    } 
} 

Чтобы иметь обработчики вне общего обработчика, вам необходимо либо иметь свой общий обработчик работать на известного типа (например,, Изменить catch (...) к catch (const my_exception& ex), и внести необходимые изменения внутри общего обработчика), или использовать вложенные try блоки:

try { 
    try { 
     whatever(); 
    } 
    catch (...) 
    { 
     standard_exception_handler(); 
    } 
} 
catch (const who_knows& ex) 
{ 
    // log and exit 
} 
0

Я могу уточнить его еще, но я понял, что я могу

С этим, мои main s не должны «знать» об этом исключений к-ExitCode перевода, которая была моей целью:

#include <stdexcept> 
#include <cstdlib> 

struct Someclass1 {}; 
struct Someclass2 {}; 

bool hasDefaultExceptionHandler = (std::set_terminate([](){ 
    try { throw; } 
    catch(const Someclass1& e){ exit(2); } 
    catch(const Someclass2& e){ exit(3); } 
    catch(...){ exit(1); } 
}), true); 

// Main has no idea 
int main(){ 
    throw Someclass2{}; 
} //will exit with 3 

Спасибо всем за хорошие идеи.

Смежные вопросы