C++ 手动抛出std::bad_alloc可以吗?
我有这个密码C++ 手动抛出std::bad_alloc可以吗?,c++,new-operator,throw,bad-alloc,C++,New Operator,Throw,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)
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_alloc之前尝试/捕获所有层创建并记录,可以吗?您不需要这样做。您可以使用
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
不是智能指针(应该是):
另一种模式是使用记录器也受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
。通常,您只能在阻塞器::~clouger()
中写出最后一个意图字符串,但对于额外的详细日志记录,您可以写出所有意图
顺便说一句,在
createEngineLayer
中,您可能需要一个捕获(…)
。如果记录器抛出一个DiskFullException
,该怎么办 为了回答这个问题(因为似乎没有其他人回答过),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::分配器相同的接口(包括行为方面的接口)
因此,如果您有一个自定义分配器(比如,一个从内存池分配的分配器),而底层分配失败,那么调用“throw std::bad_alloc”。这保证了调用方(99.9999%的时间是某种STL容器)将正确地输入它。如果分配器返回一个大的胖0,您无法控制这些STL实现将做什么-这不太可能是您喜欢的任何东西。一个小提示,如果您没有为记录器使用智能指针,那么如果CVideoLayer的构造函数抛出,这将泄漏。我在中编辑了视频层部分,因为我实际上还没有视频层(尚未)想展示我的问题。我决定让它变得简单而不是准确。如果记录器不是一个智能指针(它应该是),那么我还将添加
catch(…){delete logger;throw;}
,以防CVideoLayer构造函数引发另一个异常。如果您的对象要管理多个资源(指针),则需要使用智能指针,否则构造函数将变得非常复杂,无法正确实现。如果其分配抛出std::bad_alloc
,是否保证logger
为空?因为如果不是这样,您就有可能删除一个悬空指针。@Idan,很好的一点,logger
必须显式初始化为NULL
,以确保安全。答案相应更新,谢谢:)一般情况下,如果你甚至无法记录正在发生的事情,你想尽快打电话终止。这就是我在搜索引擎中看到问题标题时寻找的答案
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();
};
}