Domanda

Ho questo codice ..

 CEngineLayer::CEngineLayer(void)
 {
    // Incoming creation of layers. Wrapping all of this in a try/catch block is
    // not helpful if logging of errors will happen.

    logger = new (std::nothrow) CLogger(this);

    if(logger == 0)
    {
     std::bad_alloc exception;
     throw exception;
    }

    videoLayer = new (std::nothrow) CVideoLayer(this);

    if(videoLayer == 0)
    {
     logger->log("Unable to create the video layer!");

     std::bad_alloc exception;
     throw exception;
    }
 }

 IEngineLayer* createEngineLayer(void)
 {
    // Using std::nothrow would be a bad idea here as catching things thrown
    // from the constructor is needed.

    try
    {
     CEngineLayer* newLayer = new CEngineLayer;

     return (IEngineLayer*)newLayer;
    }
    catch(std::bad_alloc& exception)
    {
     // Couldn't allocate enough memory for the engine layer.
     return 0;
    }
 }

ho omesso la maggior parte delle informazioni non correlate, ma credo che il quadro è chiaro qui.

Va bene per lanciare manualmente uno std :: bad_alloc invece di try / cattura tutte le creazioni di livello individuale e di registrazione prima di rethrowing bad_allocs?

È stato utile?

Soluzione

Non c'è bisogno di fare questo. È possibile utilizzare il modulo senza parametri della dichiarazione throw per intercettare l'eccezione std::bad_alloc, log, quindi rigenerare esso:

logger = new CLogger(this);
try {
    videoLayer = new CVideoLayer(this);
} catch (std::bad_alloc&) {
    logger->log("Not enough memory to create the video layer.");
    throw;
}

O, se logger non è un puntatore intelligente (che dovrebbe essere):

logger = new CLogger(this);
try {
    videoLayer = new CVideoLayer(this);
} catch (std::bad_alloc&) {
    logger->log("Not enough memory to create the video layer.");
    delete logger;
    throw;
} catch (...) {
    delete logger;
    throw;
}

Altri suggerimenti

Proprio per rispondere alla domanda (dal momento che nessun altro sembra aver risposto), il C ++ 03 definisce standard di std::bad_alloc come segue:

namespace std {
  class bad_alloc : public exception {
  public:
    bad_alloc() throw();
    bad_alloc(const bad_alloc&) throw();
    bad_alloc& operator=(const bad_alloc&) throw();
    virtual ˜bad_alloc() throw();
    virtual const char* what() const throw();
  };
}

Dal momento che le definisce standard di un costruttore pubblico, si sarebbe perfettamente sicuro per costruire e lanciare uno dal codice. (Qualsiasi oggetto con un costruttore di copia pubblica può essere gettato, IIRC).

Io personalmente non gettarlo se uso un po 'allocatore personalizzato in contenitori STL. L'idea è di presentare lo stesso interface- anche in termini di comportamento-alle librerie STL come il default std :: allocator.

Quindi, se si dispone di un allocatore personalizzato (per esempio, una allocazione da un pool di memoria) e il sottostante allocare non riesce, chiamata "tiro std :: bad_alloc". Questo garantisce il chiamante, che 99,9999% del tempo è un po 'contenitore STL, metterà in campo in modo corretto. Lei ha alcun controllo su quali siano tali implementazioni STL faranno se l'allocatore restituisce un grosso grasso 0- è improbabile che possa essere qualcosa che ti piace.

Un altro modello è quello di utilizzare il fatto che lo strumento è soggetto a Raii anche:

CEngineLayer::CEngineLayer( )
 {
   CLogger logger(this); // Could throw, but no harm if it does.
   logger.SetIntent("Creating the video layer!");
   videoLayer = new CVideoLayer(this);
   logger.SetSucceeded(); // resets intent, so CLogger::~CLogger() is silent.
 }

Questo scala in modo pulito se ci sono più passaggi. Basta chiamare .SetIntent ripetutamente. Normalmente, si scrive solo l'ultima stringa intenti CLogger::~CLogger() ma per extra verbose la registrazione è possibile scrivere tutti gli effetti.

A proposito, nel vostro createEngineLayer si potrebbe desiderare un catch(...). Che cosa succede se il logger lancia un DiskFullException?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top