建议您始终抛出从std::exception
派生的内容,并且有一些预定义的专业化,例如std::runtime_error
std::exception
的接口是根据非投掷访问器给出的。大。现在看一下std::runtime_error
class runtime_error : public exception {
public:
explicit runtime_error (const string &);
};
所以如果我这个
try {
foo ();
}
catch (...) {
throw std :: runtime_error ("bang");
}
完全有可能foo
投掷,因为内存不足,在这种情况下构建string
runtime_error
参数也可以抛出。这将是一个throw-expression,它本身也会抛出:这不会调用std::terminate
吗?
这是不是意味着我们应该总是这样做:
namespace {
const std :: string BANG ("bang");
}
...
try {
foo ();
}
catch (...) {
throw std :: runtime_error (BANG);
}
但等待这也行不通,是吗?因为runtime_error
将复制其参数,这也可能会抛出......
...所以这不意味着没有安全的方法来使用std::exception
的标准特化,并且你应该总是滚动你自己的字符串类,其构造函数只会失败而不抛出?
或者是否有一些我不知道的技巧?
答案 0 :(得分:5)
我认为您的主要问题是您正在执行catch(...)
并转换为std::runtime_error
,从而丢失原始异常中的所有类型信息。你应该重新使用throw()
。
实际上,如果你的记忆力不足,你可能会在某个时刻抛出bad_alloc
例外,而且你可以 - 或者应该 - 做的事情并不多。如果希望因为分配失败以外的原因而抛出异常,那么构建具有有意义的上下文信息的合理异常对象可能不会有问题。如果在格式化异常对象时遇到内存问题,那么除了传播内存错误之外,你可以做很多事情。
如果你构造一个新的字符串对象来构造一个异常,那么你是对的,但是如果你想用上下文格式化一个消息,这通常是无法避免的。请注意,标准异常对象都有一个const char*
构造函数(截至上周),因此如果您想要使用const char*
,则不必构造新的std::string
对象
std::runtime_error
必须复制它的参数,但不一定是新的字符串对象。可能存在一个静态分配的内存区域,它可以将其参数的内容包含在内。它只需满足what()
要求,只需要返回const char *
,它不必存储std::string
对象。
答案 1 :(得分:3)
不,它不会。它会抛出关于内存不足的异常。控件不会到达这将是一个throw-expression,它本身也会抛出:不会这样 会调用std :: terminate?
throw
外部。
但等待这也行不通,是吗?因为runtime_error是 要复制它的论点,也可能会抛出......
使用抛出复制构造函数的异常类与抛出析构函数一样邪恶。没有什么可以真正做到的。
答案 2 :(得分:3)
std::runtime_error
旨在处理通常的运行时错误,而不是
内存不足或其他此类严重异常。基类
std::exception
不做任何可能抛出的事情;也没有
std::bad_alloc
。显然,将std::bad_alloc
重新映射到
要求动态分配工作的异常是个坏主意。
答案 3 :(得分:1)
首先,如果你碰巧遇到 bad_alloc 异常,你会想做什么,因为你内存不足?
我会说在一个经典的C ++程序中,你想让程序试图告诉你发生了什么然后终止。
在经典的C ++程序中,您可以将 bad_alloc 异常传播到程序的主要部分。主要包含像这样的尝试/捕获:
int main()
{
try
{
// your program starts
}
catch( const std::exception & e )
{
std::cerr << "huho something happened" << e.what() << std::endl;
}
catch( ... )
{
std::cerr << "huho..err..what?" << std::endl;
}
}
你只能在主要内容和线程的起始函数中使用 catch(...)。与Java等其他语言相反,您不希望在本地捕获所有可能的异常。你只要让它们传播,直到你抓住你想要的地方。
现在,如果您的代码必须特别检查 std :: bad_alloc ,那么您应该只在本地捕获(const std :: bad_alloc&amp;)。在那里做其他事情应该是明智的,而不仅仅是重新抛出另一个例外。
我在C ++编程语言§14.10中也发现,C ++异常处理机制为自己保留了一些内存以保存异常,因此抛出标准库异常本身不会引发异常。当然,如果您真的编写了变态代码,也可以让异常处理机制耗尽内存。
所以,总而言之,如果你什么都不做,并且让像 bad_alloc 这样的大型例外很好地传播到你想捕捉它们的地方,我认为你是安全的。除了主函数和线程的起始函数之外,你不应该在任何地方使用 catch(...)或 catch(const std :: exception&amp;)。
捕获所有异常以重新抛出单个异常实际上是最后一件事。您将失去使用C ++异常处理机制获得的所有优势。