我有这个代码。

 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 例外,记录它,然后重新修复:

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容器中使用一些自定义分配器,我个人会丢弃它。这个想法是在默认的std ::分配器上呈现相同的接口 - 包括行为 - 与stl库。

因此,如果您有一个自定义分配器(例如,一个从内存池分配)和基础分配失败,请调用“ throw std :: bad_alloc”。这保证了呼叫者(99.9999%的时间是某个STL容器)将适当地放置。如果分配器返回大脂肪0-不太可能是您想要的任何东西,您将无法控制这些STL实现将做什么。

另一种模式是使用该记录器也受到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