Pregunta

Tengo este código ..

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

He omitido la mayor parte de la información no relacionada, pero creo que la imagen es clara aquí.

¿Se puede tirar manualmente un std :: bad_alloc en lugar de try / captura de todas las creaciones de capa individual y el registro antes de Regeneración de bad_allocs?

¿Fue útil?

Solución

Usted no necesita hacer eso. Usted puede utilizar el formulario de la declaración sin parámetros throw para detectar la excepción std::bad_alloc, ingrese, luego volver a lanzar él:

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, si logger no es un puntero inteligente (que debe ser):

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

Otros consejos

Sólo para responder a la pregunta (ya que nadie más parece haber contestado), el C ++ 03 std::bad_alloc norma define de la siguiente manera:

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

Desde las norma define un constructor público, que sería perfectamente seguro para construir y lanzar uno de su código. (Cualquier objeto con un constructor de copia pública puede ser lanzado, IIRC).

Yo personalmente tirarlo si uso algún asignador de costumbre en contenedores STL. La idea es presentar la misma interface- incluso en términos de comportamiento: a las bibliotecas STL como el valor por defecto std :: asignador.

Por lo tanto, si usted tiene un asignador de costumbre (por ejemplo, una asignación de un banco de memoria) y el subyacente asignar falla, llamada "tiro std :: bad_alloc". Que garantice la persona que llama, que el 99,9999% de las veces es un poco de contenedores STL, alineará correctamente. Usted no tiene control sobre lo que esas implementaciones STL harán si el asignador devuelve un grande y gordo 0- es poco probable que sea algo que te gusta.

Otro patrón es usar el hecho de que el registrador está sujeta a RAII, también:

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

Esta escalas limpiamente si hay varios pasos. Tu solo .SetIntent repetidamente. Normalmente, sólo se escribe la última cadena intención de CLogger::~CLogger() pero para extra de registro detallado se puede escribir todos los intentos.

Por cierto, en su createEngineLayer es posible que desee un catch(...). ¿Qué pasa si el registrador lanza una DiskFullException?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top