2013-01-09 14 views

risposta

9

L'utilizzo di std::current_exception sembra un po 'esagerato nel tuo caso, dal momento che non sembra voler memorizzare o copiare lo std::exception_ptr per l'elaborazione successiva (che è il suo unico scopo, non aiuta a ottenere ulteriori informazioni su un'eccezione sconosciuta in alcun modo). Se si desidera solo per trattare il caso di un std::exception, per quanto riguarda la semplice:

try 
{ 
    // code throws potentially unknown exception 
} 
catch (const std::exception &e) 
{ 
    std::cerr << e.what() << '\n'; // or whatever 
} 
catch (...) 
{ 
    // well ok, still unknown what to do now, 
    // but a std::exception_ptr doesn't help the situation either. 
    std::cerr << "unknown exception\n"; 
} 
+1

Allora qual è esattamente il vero uso di std :: exception_ptr? – Ram

+7

@Ram Il suo utilizzo è per la memorizzazione e la copia di un'eccezione (che può avere un tipo arbitrario). È una sorta di puntatore intelligente proprietario. Immagina che sia come un 'std :: shared_ptr ', solo che funziona per qualsiasi eccezione di qualunque tipo (motivo per cui non fornisce alcuna informazione di tipo). Ciò è particolarmente utile per propagare le eccezioni tra i thread, dove ad es. un 'std :: promise' ha bisogno di * archiviare * un'eccezione occulta da ripassare più tardi quando si prova ad accedere al valore di' std :: future' in un altro thread. –

+2

@Ram Alla fine è utile ogni volta che si desidera memorizzare un'eccezione generata per un uso successivo (dato che normalmente verrà distrutta al termine del blocco catch). Vedi [this] (http://en.cppreference.com/w/cpp/error/exception_ptr) e le relative pagine. –

12
try 
{ 
    std::rethrow_exception(eptr); 
} 
catch (const std::exception& e) 
{ 
    std::cerr << e.what() << std::endl; 
} 

http://en.cppreference.com/w/cpp/error/exception_ptr

+4

Probabilmente dovresti fare qualcosa sul caso in cui l'eccezione * non * deriva anche da 'std :: exception' ... –

+0

Bene nel caso dell'OP che è altamente ridondante poiché OP è già in un blocco' catch' . E in generale, non penso che funzionerebbe dato che potrebbe interferire con un'eccezione già generata. –

+0

@KerrekSB si, forse dovremmo rilevare qualche eccezione e stampare qualcosa su "errore sconosciuto" ... KonradRudolph comunque, non c'è altro caso per standard. Possiamo scrivere la funzione e chiamarla dopo un blocco try/catch. – ForEveR

1

Non è la soluzione migliore, a mio parere, ma sembra funzionare.

try 
{ 
// code throws potentially unknown exception 
} 
catch (const std::exception& e) 
{ 
    std::cerr << e.what() << std::endl; 
} 
catch (...) 
{ 
    std::exception_ptr eptr = std::current_exception(); 
     // then what ? 
    LogUnknownException(); 
} 

Grazie per sempre per la soluzione iniziale, ma non sono sicuro se voglio rilanciare all'interno del blocco catch.

+1

L'uso di 'current_exception' qui è inutile, non aggiunge nulla. –

4

// allora che cosa?

qui è quello che:

#include <exception> 
#include <stdexcept> 
#include <iostream> 
#include <string> 

std::string what(const std::exception_ptr &eptr = std::current_exception()) 
{ 
    if (!eptr) { throw std::bad_exception(); } 

    try { std::rethrow_exception(eptr); } 
    catch (const std::exception &e) { return e.what() ; } 
    catch (const std::string &e) { return e   ; } 
    catch (const char   *e) { return e   ; } 
    catch (...)      { return "who knows"; } 
} 

int main() 
{ 
    try { throw std::runtime_error("it's success!"); } 
    catch (...) { std::cerr << "Here is WHAT happened: " << what() << std::endl; } 

    try { throw 42; } catch (...) { std::cerr << "and now what: " << what() << std::endl; } 
} 

cosa esso stampa:

Here is WHAT happened: it's success! 
and now what: who knows 

http://coliru.stacked-crooked.com/a/1851d2ab9faa3a24

quindi questo permette di ottenere what nella clausola onnicomprensiva.

ma cosa succede se l'eccezione è nidificata ??? qui è quello che:

std::string what(const std::exception_ptr &eptr = std::current_exception()); 

template <typename T> 
std::string nested_what(const T &e) 
{ 
    try   { std::rethrow_if_nested(e); } 
    catch (...) { return " (" + what(std::current_exception()) + ")"; } 
    return {}; 
} 

std::string what(const std::exception_ptr &eptr) 
{ 
    if (!eptr) { throw std::bad_exception(); } 

    try { std::rethrow_exception(eptr); } 
    catch (const std::exception &e) { return e.what() + nested_what(e); } 
    catch (const std::string &e) { return e   ; } 
    catch (const char   *e) { return e   ; } 
    catch (...)      { return "who knows"; } 
} 

usando esempio dalla here:

#include <fstream> 

... 

// sample function that catches an exception and wraps it in a nested exception 
void open_file(const std::string& s) 
{ 
    try { 
     std::ifstream file(s); 
     file.exceptions(std::ios_base::failbit); 
    } catch(...) { 
     std::throw_with_nested(std::runtime_error("Couldn't open " + s)); 
    } 
} 

// sample function that catches an exception and wraps it in a nested exception 
void run() 
{ 
    try { 
     open_file("nonexistent.file"); 
    } catch(...) { 
     std::throw_with_nested(std::runtime_error("run() failed")); 
    } 
} 

int main() 
{ 
    try { throw std::runtime_error("success!"); } 
    catch (...) { std::cerr << "Here is WHAT happened: \"" << what() << '\"' << std::endl; } 

    try { run(); } 
    catch (...) { std::cerr << "what happened for run: \"" << what() << '\"' << std::endl; } 
} 

ciò che è stampato:

Here is WHAT happened: "success!" 
what happened for run: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))" 

http://coliru.stacked-crooked.com/a/901a0c19297f02b5

ma cosa succede se ricorsione troppo profondo? cosa succede se stackoverflow?ottimizzato quali:

#include <typeinfo> 

template <typename T> 
std::exception_ptr get_nested(const T &e) 
{ 
    try 
    { 
     auto &nested = dynamic_cast<const std::nested_exception&>(e); 
     return nested.nested_ptr(); 
    } 
    catch (const std::bad_cast &) 
     { return nullptr; } 
} 

#if 0 // alternative get_nested 
    std::exception_ptr get_nested() 
    { 
     try         { throw    ; } 
     catch (const std::nested_exception &e) { return e.nested_ptr(); } 
     catch (...)       { return nullptr  ; } 
    } 
#endif 

std::string what(std::exception_ptr eptr = std::current_exception()) 
{ 
    if (!eptr) { throw std::bad_exception(); } 

    std::string whaaat; 
    std::size_t num_nested = 0; 
    next: 
    { 
     try 
     { 
      std::exception_ptr yeptr; 
      std::swap(eptr, yeptr); 
      std::rethrow_exception(yeptr); 
     } 
     catch (const std::exception &e) { whaaat += e.what() ; eptr = get_nested(e); } 
     catch (const std::string &e) { whaaat += e   ; } 
     catch (const char   *e) { whaaat += e   ; } 
     catch (...)      { whaaat += "who knows"; } 

     if (eptr) { whaaat += " ("; num_nested++; goto next; } 
    } 
    whaaat += std::string(num_nested, ')'); 
    return whaaat; 
} 

la stessa cosa:

Here is WHAT happened: "success!" 
here is what: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))" 

http://coliru.stacked-crooked.com/a/32ec5af5b1d43453

UPD

La funzionalità simile può essere implementata in C++ 03 utilizzando un trucco che permette per re throw eccezione corrente al di fuori del blocco catch: https://stackoverflow.com/a/3641809/5447906

+0

Invece di 'dynamic_cast' -' catch bad_cast' - 'return nullptr', dovresti semplicemente' dynamic_cast' un puntatore invece di un riferimento. – Miral

Problemi correlati