Вопрос

У меня есть этот код ..

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

Я опущел большую часть не связанной информации, но я думаю, что картинка здесь ясно.

Это нормально, чтобы вручную бросить std :: bad_alloc вместо того, чтобы попробовать / ловить все творения слоев индивидуально и входить в лесозаготовку перед вентиляцией bad_allocs?

Это было полезно?

Решение

Вам не нужно это делать. Вы можете использовать форму без параметра throw заявление, чтобы поймать std::bad_alloc Исключение, войти в систему, затем Rethrow это:

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

Или если logger не умный указатель (который это должно быть):

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

Другие советы

Просто чтобы ответить на вопрос (так как никто другой, кажется, не ответил на него), стандарт C ++ 03 определяет std::bad_alloc следующим образом:

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

Поскольку стандарт определяет общественный конструктор, вы бы идеально в безопасности построить и бросить один из вашего кода. (Любой объект с конструктором публичных копий можно бросить, IIRC).

Я лично бросаю это, если я использую какой-то пользовательский распределитель в контейнерах STL. Идея состоит в том, чтобы представить тот же интерфейс, в том числе с точки зрения поведения - к библиотекам STL как по умолчанию STD :: allocator.

Итак, если у вас есть пользовательский распределитель (скажем, один, выделяющий из пула памяти), а базовый распределитель не удается, позвоните «бросить std :: bad_alloc». Это гарантирует абонент, который 99,99999% времени - это какой-то контейнер STL, приведет его должным образом. Вы не контролируете то, что эти реализации STL сделают, если распределитель возвращает большой жир 0 - вряд ли будет все, что вам понравится.

Другой шаблон состоит в том, чтобы использовать тот факт, что регистратор подчиняется Raii тоже:

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

Это масштабируется чисто, если есть несколько шагов. Вы просто звоните .SetIntent неоднократно. Обычно вы только выписываете последнюю намеренную строку в CLogger::~CLogger() Но для лишних весовых веществ вы можете записать все намерения.

Кстати, в вашем createEngineLayer Возможно, вы захотите catch(...). Отказ Что если регистратор бросает DiskFullException?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top