Question

Je le code ..

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

J'ai omis la plupart des informations non liées, mais je pense que l'image est clair.

Est-il correct de jeter manuellement un std :: bad_alloc au lieu d'essayer / attraper toutes les créations de la couche individuellement et l'exploitation forestière avant rethrowing bad_allocs?

Était-ce utile?

La solution

Vous n'avez pas besoin de le faire. Vous pouvez utiliser le formulaire de la déclaration parameterless de throw pour attraper l'exception std::bad_alloc, connectez-il, réémettre il:

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

Ou, si logger est pas un pointeur intelligent (il devrait être):

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

Autres conseils

Juste pour répondre à la question (puisque personne ne semble autre avoir répondu), le C ++ 03 définit standards std::bad_alloc suit comme:

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

Puisque la norme définit un constructeur public, vous seriez tout à fait sûr de construire et jeter un à partir de votre code. (Tout objet avec un constructeur de copie publique peut être jeté, IIRC).

Personnellement, je ne le jeter si je l'utilise un peu allocateur personnalisé dans des conteneurs STL. L'idée est de présenter le même interface- y compris en termes de behavior- aux bibliothèques STL comme la valeur par défaut std :: allocateur.

Donc, si vous avez un allocateur personnalisé (par exemple, une allocation d'un pool de mémoire) et le sous-jacent allocation tombe en panne, appel « jeter std :: bad_alloc ». Cela garantit l'appelant, qui 99,9999% du temps est un certain conteneur STL, il sera le terrain correctement. Vous avez aucun contrôle sur ce que les implémentations STL faire si l'allocateur retourne un gros 0- il est peu probable d'être tout ce que vous aimerez.

Une autre tendance est d'utiliser le fait que l'enregistreur est soumis à RAII aussi:

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

échelles proprement s'il y a plusieurs étapes. Vous venez d'appeler .SetIntent à plusieurs reprises. Normalement, vous écrivez que la dernière chaîne intention dans CLogger::~CLogger() mais pour de plus bavard vous connecter pouvez écrire toutes les intentions.

BTW, dans votre createEngineLayer vous voudrez peut-être un catch(...). Que faire si l'enregistreur jette un DiskFullException?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top