2010-03-19 8 views
7

Ci sono alcuni articoli che concludono "mai un'eccezione da un distruttore", e "std :: uncaught_exception() non è utile", per esempio:diritti d'uso di std :: uncaught_exception in un distruttore

Ma a quanto pare non ho capito il punto. Così ho scritto un piccolo esempio di test (vedi sotto).

Dato che tutto va bene con l'esempio di test, apprezzerei molto i commenti su cosa potrebbe esserci di sbagliato in questo?

risultati della prova:

./main

 
    Foo::~Foo(): caught exception - but have pending exception - ignoring 
    int main(int, char**): caught exception: from int Foo::bar(int) 

./main 1

 
    Foo::~Foo(): caught exception - but *no* exception is pending - rethrowing 
    int main(int, char**): caught exception: from Foo::~Foo() 

esempio:

// file main.cpp 
// build with e.g. "make main" 
// tested successfully on Ubuntu-Karmic with g++ v4.4.1 
#include <iostream> 

class Foo { 
    public: 

    int bar(int i) { 
    if (0 == i) 
     throw(std::string("from ") + __PRETTY_FUNCTION__); 
    else 
     return i+1; 
    } 

    ~Foo() { 
    bool exc_pending=std::uncaught_exception(); 
    try { 
     bar(0); 
    } catch (const std::string &e) { 
     // ensure that no new exception has been created in the meantime 
     if (std::uncaught_exception()) exc_pending = true; 

     if (exc_pending) { 
     std::cerr << __PRETTY_FUNCTION__ 
        << ": caught exception - but have pending exception - ignoring" 
        << std::endl; 
     } else { 
     std::cerr << __PRETTY_FUNCTION__ 
        << ": caught exception - but *no* exception is pending - rethrowing" 
        << std::endl; 
     throw(std::string("from ") + __PRETTY_FUNCTION__); 
     } 
    } 
    } 

}; 

int main(int argc, char** argv) { 
    try { 
    Foo f; 
    // will throw an exception in Foo::bar() if no arguments given. Otherwise 
    // an exception from Foo::~Foo() is thrown. 
    f.bar(argc-1); 
    } catch (const std::string &e) { 
    std::cerr << __PRETTY_FUNCTION__ << ": caught exception: " << e << std::endl; 
    } 
    return 0; 
} 

AGGIUNTI : In altre parole: nonostante gli avvertimenti in alcuni articoli funziona come previsto, quindi cosa potrebbe esserci di sbagliato?

+2

Qual è la tua domanda? Sembra che tu stia osservando il comportamento previsto di un meccanismo che non dovresti usare. Stai pensando di usarlo al di fuori di un contesto di sperimentazione/sperimentazione e perché? – Potatoswatter

+0

@Potatoswatter: la domanda è: 'nonostante gli avvertimenti in alcuni articoli funziona come previsto - quindi cosa potrebbe esserci di sbagliato?' –

+0

Fair nug, ma questo non sta citando quello che hai detto, ed è impossibile sapere cosa ci si aspetta, appropriato, o sicuro nel tuo contesto senza ulteriori informazioni. La via sicura, come Herb Sutter e molti altri ti diranno, non è di buttare da un distruttore in primo luogo. – Potatoswatter

risposta

5

Non c'è niente di tecnicamente sbagliato nel codice. È perfettamente sicuro in quanto non terminerai mai accidentalmente perché hai lanciato un'eccezione quando non era sicuro. Il problema è che non è utile, in quanto occasionalmente non genera nemmeno un'eccezione quando è sicuro. La documentazione del tuo distruttore dice fondamentalmente "questo potrebbe o non potrebbe generare un'eccezione".

Se occasionalmente non si genera un'eccezione, si potrebbe anche non generare mai un'eccezione. In questo modo, sei almeno coerente.

6

Herb Sutter fa riferimento a un altro problema. Sta parlando di:

try 
{ 
} 
catch (...) 
{ 
    try 
    { 
     // here, std::uncaught_exception() will return true 
     // but it is still safe to throw an exception because 
     // we have opened a new try block 
    } 
    catch (...) 
    { 
    } 
} 

Quindi il problema è che se std::uncaught_exception() restituisce vero non si sa con certezza se si può buttare tranquillamente un'eccezione oppure no. Si finisce per evitare di lanciare un'eccezione quando std::uncaught_exception() restituisce true solo per sicurezza.

+0

@ Samuel: '... riferendosi a un altro problema ...' Questo è quello che pensavo anche io. E poiché non lancio un'eccezione quando uncaught_exception() restituisce true, credi che il mio approccio sia sicuro? –

+0

In realtà non è corretto. La tua eccezione viene catturata a quel punto. Dovresti aver messo il try/catch in un distruttore, che è invocato mentre lo stack si slega (a causa di un'eccezione attiva). In questa situazione, un'eccezione * è * attivamente per srotolare lo stack, ma tu sei proprio allora all'interno di un blocco try/catch in cui puoi * lanciare un'eccezione. – dascandy

Problemi correlati