domain_error(const string& what_arg);
domain_error(const char* what_arg);
与后置条件
strcmp(what(), what_arg.c_str()) == 0
strcmp(what(), what_arg) == 0
分别。没有要求传递给构造函数的参数在这些例外的生命周期内保持有效,因此确保后置条件的唯一方法是重复并存储这些动态字符串。这需要记忆力,所以我假设他们的构造本身可能会抛出std::bad_alloc
或类似的东西,这通常是最意想不到的。这会导致问题,因为我已经在野外看到的每一个代码示例鼓励人们写代码像
if (haveError)
throw std::runtime_error("BOO!"); // May throw std::bad_alloc instead?!
,而它似乎要安全得多预先构建的例外在其他一些地方,如:
struct A {
// During allocation of A one would often expect std::bad_alloc anyway:
A() : m_someException("BOO!") {}
void f() {
/* Do stuff */
if (haveError)
throw m_someException;
/* Note that according to §18.8.1.2 all standard library
classes deriving from `std::exception` must have publicly
accessible copy constructors and copy assignment operators
that do not exit with an exception. In implementations such
exception instances most likely share the common string
with all their copies. */
}
std::runtime_error const m_someException;
};
这使我非常谨慎的库,抛出任何这样的例外,例如,甚至regex_error
从<regex>
在C + + 11!
为什么这些例外不具有no-throw/noexcept构造函数? C++核心指南是否对此有发言权?
PS:就我个人而言,我会在异常血统链的这一点上留下what()
一个纯粹的抽象方法。
编辑2017年9月10日:这里的PoC证明std::runtime_error
建设可以抛出一个std::bad_alloc
代替:
#include <cstddef>
#include <cstdlib>
#include <new>
#include <stdexcept>
#include <string>
bool throwOnAllocate = false;
void * operator new(std::size_t size) {
if (!throwOnAllocate)
if (void * const r = std::malloc(size))
return r;
throw std::bad_alloc();
}
void operator delete(void * ptr) { std::free(ptr); }
int main() {
std::string const errorMessage("OH NOEZ! =(");
throwOnAllocate = true;
throw std::runtime_error(errorMessage);
}
是的,它可能是一个函数不会执行,因为在那个瞬间缺少未使用的堆内存,但显示错误'alert'实际上会冻结或崩溃系统。谢天谢地,这很少见。 –
“,而在其他地方事先构建例外似乎更安全” - 我不明白。如果你的'throw std :: runtime_error(“BOO!”);'由于内存不足而抛出了一个不同的异常,事先分配'std :: runtime_error'仍然会*要求内存可用。我看到的唯一变化是'bad_alloc'会在之前被抛出。 – hvd
@ hvd早些时候在一些更好的或**预期的**上下文中,例如'新的A()'。在错误/异常处理(包括C++ 11异常嵌套上下文)期间,意外地发生异常**被抛出是非常糟糕的。 – jotik