2015-12-08 6 views
8

In jeder meiner Hauptfunktionen möchte ich bestimmte Klassen von Ausnahmen abfangen und sie in Exit-Codes konvertieren.Ein impliziter Versuch {} catch around main

Gibt es eine elegantere Lösung als das Starten und Beenden jeder Hauptfunktion mit Makros, die die implizite try {} catch Ich möchte einfügen?

Kann ich das irgendwie mit der std::set_terminate Funktionalität erreichen?

Beispiel:

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

Sind alle Ihre Ausnahmen durch Vererbung (oder könnten sie?) – quamrana

+0

@quamrana Ja. Es könnte tatsächlich nur eine einzige virtuelle Basisklasse sein. – PSkocik

+2

Sie können dann jede Ausnahmeklasse den Return-Code einbetten lassen und ein einzelnes try/catch in 'main()' könnte es extrahieren und zurückgeben. – quamrana

Antwort

6

Eine clean way beinhaltet die Verwendung einer Übersetzungsfunktion mit all Ihren Exception-Boilerplate, die die Exit-Werte für die entsprechende Ausnahme zurückgibt.

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

In Ihrem eigenen Code, können Sie sich nur beziehen sich auf Ihre Business-Logik mit einem Lambda mit Einwickeln und übergeben, daß in die Funktion Übersetzung, so dass es erfassen kann und für Sie übersetzen.

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

I so zweifeln. Zu dem Zeitpunkt, zu dem terminal aufgerufen wird, haben Sie bereits alle Ausnahmeinformationen verloren (genauer gesagt, Sie hatten es nie - terminate wird aufgerufen, wenn keine Handler verfügbar sind und dann die Bestimmung an der Call-Site erfolgt). Ausnahmeobjekt wird nicht einmal erstellt, wenn es keinen passenden Handler dafür gibt.

1

Ich denke, Sie könnte etwas mit Makros tun, wenn Sie wollen. Hier ist, wie:

#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 

Die Idee ist, das Makro schreiben einen Versuch fangen „um“ die Hauptfunktion Körper zu lassen, die alle legal ist.

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

little example live

1

ich dies normalerweise tun:

int main2(); 

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

Sie mehr catch-Handler natürlich haben können.


Wenn Sie die gleiche Liste von Fang-Handler in mehrere Einstiegspunkte setzen müssen, das wäre eine andere Frage sein. Die Lösung dort soll catch(...) { foo(); } haben, wo die foo() Funktion try { throw; } gefolgt von allen Fanghandlern tut.

0

Die cleanest solution ich mit Blicken wie vertraut bin:

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) 
    { 
     ... 
    } 
} 

Um Handler außerhalb des gemeinsamen Handler zu haben, müssen Sie entweder Ihre gemeinsamen Handler auf einer bekannten Art arbeiten müssen (zändern, catch (...)-catch (const my_exception& ex) und erforderliche Änderungen innerhalb des gemeinsamen Handler), oder benutzen Sie verschachtelte try Blöcke:

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

ich es noch verfeinern kann, aber ich herausgefunden, ich kann

Damit meine main s müssen nicht "wissen" über diese Ausnahme-to-Exit-Wert Übersetzung, die mein Ziel war:

#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 

Danke an alle für die guten Ideen.