C++ 手动抛出 std::bad_alloc 可以吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4357719/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it okay to manually throw an std::bad_alloc?
提问by Jookia
I have this 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;
}
}
I've omitted most of the non-related information, but I think the picture is clear here.
我省略了大部分不相关的信息,但我认为这里的图片很清楚。
Is it okay to manually throw an std::bad_alloc instead of try/catching all of the layer creations individually and logging before rethrowing bad_allocs?
是否可以手动抛出 std::bad_alloc 而不是在重新抛出 bad_allocs 之前单独尝试/捕获所有图层创建并记录?
采纳答案by Frédéric Hamidi
You don't need to do that. You can use the parameterless form of the throw
statement to catch the std::bad_alloc
exception, log it, then rethrow it:
你不需要这样做。您可以使用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;
}
Or, if logger
is not a smart pointer (which it should be):
或者,如果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;
}
回答by Daryl
Just to answer the question (since nobody else seems to have answered it), the C++03 standard defines std::bad_alloc
as follows:
为了回答这个问题(因为似乎没有其他人回答过),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();
};
}
Since the standard defines a public constructor, you'd be perfectly safe to construct and throw one from your code. (Any object with a public copy constructor can be thrown, IIRC).
由于标准定义了一个公共构造函数,因此您可以完全安全地从代码中构造和抛出一个构造函数。(任何具有公共复制构造函数的对象都可以抛出,IIRC)。
回答by Zack Yezek
I personally DO throw it if I use some custom allocator in STL containers. The idea is to present the same interface- including in terms of behavior- to the STL libraries as the default std::allocator.
如果我在 STL 容器中使用一些自定义分配器,我个人会抛出它。这个想法是向 STL 库提供相同的接口——包括行为方面的——作为默认的 std::allocator。
So, if you have a custom allocator (say, one allocating from a memory pool) and the underlying allocate fails, call "throw std::bad_alloc". That guarantees the caller, who 99.9999% of the time is some STL container, will field it properly. You have no control over what those STL implementations will do if the allocator returns a big fat 0- it is unlikely to be anything you'll like.
因此,如果您有一个自定义分配器(例如,一个从内存池分配)并且底层分配失败,请调用“throw std::bad_alloc”。这保证了在 99.9999% 的时间是某个 STL 容器的调用者将正确地字段它。如果分配器返回一个很大的 0,您无法控制那些 STL 实现将做什么 - 它不太可能是您喜欢的任何东西。
回答by MSalters
Another pattern is to use the fact that the logger is subject to RAII, too:
另一种模式是利用记录器也受 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.
}
This scales cleanly if there are multiple steps. You just call .SetIntent
repeatedly. Normally, you only write out the last intent string in CLogger::~CLogger()
but for extra verbose logging you can write out all intents.
如果有多个步骤,这可以干净地缩放。你只是.SetIntent
反复打电话。通常,您只写出最后一个意图字符串,CLogger::~CLogger()
但对于更详细的日志记录,您可以写出所有意图。
BTW, in your createEngineLayer
you might want a catch(...)
. What if the logger throws a DiskFullException
?
顺便说一句,在createEngineLayer
你可能想要一个catch(...)
. 如果记录器抛出DiskFullException
?