std异常邀请不安全的用法?

spr*_*aff 4 c++ constructor exception-handling exception std

建议您始终抛出从中派生的东西,std::exception并且有一些预定义的特化,例如std::runtime_error

std::exception的界面是根据非投掷访问器给出的.大.现在看一下构造函数std::runtime_error

class runtime_error : public exception {
public:
  explicit runtime_error (const string &);
};
Run Code Online (Sandbox Code Playgroud)

所以,如果我做

try {
    foo ();
}
catch (...) {
    throw std :: runtime_error ("bang");
}
Run Code Online (Sandbox Code Playgroud)

完全有可能foo抛出因为内存不足,在这种情况下构造string参数runtime_error也可以抛出.这将是一个throw-expression,它本身也会抛出:这不会叫std::terminate吗?

这是不是意味着我们应该总是这样做:

namespace {
    const std :: string BANG ("bang");
}

...

try {
    foo ();
}
catch (...) {
    throw std :: runtime_error (BANG);
}
Run Code Online (Sandbox Code Playgroud)

但等等,这也行不通,是吗?因为runtime_error要复制它的论点,这也可能会引发......

...所以这是不是意味着没有安全的方法来使用标准的特化std::exception,并且你应该总是滚动你自己的字符串类,其构造函数只会失败而不抛出?

还是有一些我不知道的伎俩?

CB *_*ley 5

我认为您的主要问题是您正在进行catch(...)并转换为std::runtime_error从而丢失原始异常中的所有类型信息.你应该重新考虑一下throw().

实际上,如果你缺乏记忆力,你可能会bad_alloc在某个时刻抛出异常,而且你可以 - 或者应该 - 做的事情也不多.如果由于分配失败以外的原因而抛出异常,那么构建具有有意义的上下文信息的合理异常对象可能不会有问题.如果在格式化异常对象时遇到内存问题,那么除了传播内存错误之外,您可以做很多事情.

如果你构造一个新的字符串对象来构造一个异常,那么你是对的,但是如果你想用上下文格式化一个消息,这通常是无法避免的.请注意,标准异常对象都有一个const char*构造函数(截至上周),因此如果您有一个const char*想要使用的构造函数,则不必构造新std::string对象.

std::runtime_error必须复制它的参数,但不一定是新的字符串对象.可能存在一个静态分配的内存区域,它可以将其参数的内容包含在内.它只需要满足what()只需要返回a 的要求const char *,它不需要存储std::string对象.