Подтвердить что ты не робот

Можно ли вручную запустить std:: bad_alloc?

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

 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?

4b9b3361

Ответ 1

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

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

Ответ 2

Чтобы ответить на вопрос (так как никто больше не ответил на него), стандарт С++ 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).

Ответ 3

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

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

Ответ 4

Другой шаблон - использовать тот факт, что логгер тоже подвержен 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?