2011-10-10 18 views
5

Il seguente esempio lasciare una possibile perdita di memoria perché il distruttore non viene eseguito per l'oggetto su cui viene gestito l'eccezione durante il costruttore viene eseguito. dove gestisco questa perdita di memoria?Facendo eccezioni nel costruttore

#include <exception> 

class MyClass { 

public: 
     MyClass() 
     { 
      c = new char[5]; 
      throw std::runtime_error("test"); 
     } 

     ~MyClass() 
     { 
      delete[] c; 
     } 

private: 
    char *c; 
}; 

int main() 
{ 
    try 
    { 
     MyClass Obj; 

    } 
    catch (std::runtime_error) 
    { 

    } 
} 

risposta

5

Si sta meglio utilizzando RAII, puntatore intelligente in questo caso per essere precisi.

In alternativa, è possibile utilizzare la strategia Two Phased Construction.

Si può sempre usare racchiude try-catch blocchi all'interno del corpo costruttore e chiamare in modo esplicito eliminare per tutte quelle risorse che si allocata dinamicamente a meno di pensare lo scenario in cui si dispone di n numero di risorse in fase di allocata dinamicamente, diventa davvero disordinato di tenere esplicitamente pista di ogni risorsa che è necessario deallocare nel catch, in un tale scenario, RAII vi dà la soluzione migliore perché poi ogni risorsa prende implicitamente cura della propria deallocation e non bisogno di avere il sovraccarico di tenere traccia di ogni risorsa.

boost::scoped_ptr o std::tr1::scoped_ptr sono adatti per questo scenario anziché per i puntatori grezzi.

+2

Che cosa richiede questo downgrade? RAII è il modo migliore per farlo e, se qualcuno dice diversamente, non è corretto. Se ti senti responsabile di Downvote, sentiti abbastanza responsabile da spiegarci perché? E se non puoi e semplicemente * senti * questo è sbagliato, allora non sei qualificato per fare downvoting, lascia che sia qualcun altro a farlo. –

+0

è questa soluzione basata su roba relativa al C++ 11? – user103214

+0

No, questo è C++ 03. –

6

Catch l'eccezione nel costruttore, riordinare (deallocare la memoria), quindi lanciare l'eccezione senza la perdita di memoria.

+0

Il distruttore non è mai stato chiamato quando ho rilanciato l'eccezione senza perdite di memoria nel costruttore. c'è qualche ragione per questo? – user103214

+1

@ user974191: la costruzione dell'oggetto non è completa fino alla parentesi finale del costruttore. Il distruttore viene chiamato solo per l'oggetto che è completo. Se il costruttore non è stato eseguito completamente, l'oggetto non esiste e quindi non verrà chiamato nessun distruttore. –

1

si può prendere l'eccezione nel corpo del costruttore, fate quello che avete bisogno di pulizia, quindi rethrow l'eccezione con throw;

Detto questo, eccezioni e movimentazione manuale della memoria non vanno bene insieme. Sarete molto meglio usando un oggetto che gestisce automaticamente la memoria per il membro c (es std::string, std::vector<char>, std::unique_ptr<char[]> ecc). Devi davvero gestire la memoria in modo esplicito se stai scrivendo una classe come quella di cui sopra, il cui scopo è esattamente quello di occuparsi di quella memoria.

4

Un modo è quello di throw l'eccezione condizionale all'inizio del costruttore e quindi allocare la memoria.

MyClass() 
    { 
    if(<condition>) 
     throw std::runtime_error("test"); 
    c = new char[<SIZE>]; 
    } 

altro modo è quello di utilizzare la sintassi speciale try-catch() allegando il costruttore:

MyClass() 
    try { 
    c = new char[5]; 
    throw std::runtime_error("test");; 
    } 
    catch(std::runtime_error e) { 
    delete[] c; 
    } 

Demo.

Problemi correlati