请查看以下抛出和捕获异常:
void some_function() {
throw std::exception("some error message");
}
int main(int argc, char **argv) {
try {
some_function();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
exit(1);
}
return 0;
}
通过引用捕获抛出的异常是否安全?
我担心的是,例外e
实际上是置于some_function()
的堆栈。但是some_function()
刚刚返回,导致e
被破坏。实际上现在e
指向被破坏的对象。
我的担忧是否正确?
传递异常而不按值复制它的正确方法是什么?我应该抛出new std::exception()
以便将它放在动态内存中吗?
答案 0 :(得分:93)
const
引用确实是安全的 - 并且建议使用。
“
的堆栈上e
实际上放在some_function()
”
不,它不是......实际抛出的对象是在一个未指定的内存区域中创建的,该区域保留供异常处理机制使用:
[except.throw] 15.1 / 4:异常对象的内存以未指定的方式分配,除非在3.7.4.1中说明。异常 在通过除了重新抛出之外的任何方式退出异常的最后一个活动处理程序之后,对象被销毁,或者引用异常对象的std :: exception_ptr(18.8.5)类型的最后一个对象被销毁,以较晚者为准。 / p>
如果为throw
指定了局部变量,则必要时将其复制到那里(优化器可能能够在其他内存中直接创建它)。这就是为什么......
15.1 / 5 当抛出的对象是类对象时,为复制初始化和析构函数选择的构造函数 即使复制/移动操作被省略(12.8),也应该是可访问的。
如果没有点击,可能有助于想象实现模糊地这样:
// implementation support variable...
thread__local alignas(alignof(std::max_align_t))
char __exception_object[EXCEPTION_OBJECT_BUFFER_SIZE];
void some_function() {
// throw std::exception("some error message");
// IMPLEMENTATION PSEUDO-CODE:
auto&& thrown = std::exception("some error message");
// copy-initialise __exception_object...
new (&__exception_object) decltype(thrown){ thrown };
throw __type_of(thrown);
// as stack unwinds, _type_of value in register or another
// thread_local var...
}
int main(int argc, char **argv)
{
try {
some_function();
} // IMPLEMENTATION:
// if thrown __type_of for std::exception or derived...
catch (const std::exception& e) {
// IMPLEMENTATION:
// e references *(std::exception*)(&__exception_object[0]);
...
}
}
答案 1 :(得分:22)
你有通过引用捕获,否则你无法获得正确的动态类型的对象。至于它的生命周期,标准保证在[except.throw]
,
异常对象在异常的最后剩余活动处理程序以除了重新抛出之外的任何方式退出之后被销毁,或者引用异常对象的类型为std :: exception_ptr(18.8.5)的最后一个对象被销毁,以较晚者为准
答案 2 :(得分:18)
通过const引用捕获完全应该如何捕获异常。异常对象不一定生活在堆栈上。编译器负责使这项工作具有适当的魔力。
另一方面,您的示例无法编译,因为std::exception
可能只是默认构造或复制构造。在这种情况下,what()
方法将返回一个指向空(c样式)字符串的指针,这不是特别有用。
建议您根据需要抛出std::runtime_error
或std::logic_error
或从中派生的类:
logic_error
当来电者请求了服务设计参数之外的内容时。runtime_error
当来电者请求合理的内容但外部因素阻止您尊重请求时。 答案 3 :(得分:8)