引用危险是否引发exception?
请看下面的exception抛出和捕获:
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; }
通过引用来捕捉抛出的exception是否安全?
我的担心是因为exceptione
实际上放置在 some_function()
的堆栈上。 但是some_function()
刚刚返回,导致e
被破坏。 所以现在实际上e
指向一个被破坏的对象。
我关心的是正确的吗?
传递exception但不按值复制的正确方法是什么? 我应该抛出new std::exception()
所以它被放置在dynamic内存?
确实是安全的 – 并build议 – 通过常参考。
“
e
实际上是放置在some_function()
的堆栈上”
不,它不是…实际抛出的对象被创build在保留供exception处理机制使用的未指定内存区域中:
[except.throw] 15.1 / 4: exception对象的内存以未指定的方式分配,除非在3.7.4.1中提到。 exception对象在exception的最后剩余活动处理程序以重新抛出之外的任何方式退出之后被销毁,或者引用exception对象的typesstd :: exception_ptr(18.8.5)的最后一个对象被销毁,以较晚者为准。
如果指定了一个局部variables来throw
,那么它将被复制到那里(如果有必要,优化器可以直接在其他内存中创build它)。 这就是为什么…
15.1 / 5 当抛出的对象是一个类对象时,即使复制/移动操作被取消(12.8),为复制初始化和析构函数select的构造函数也应该是可访问的。
如果没有点击,这可能有助于想象执行含糊不清:
// 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]); ... } }
你必须通过引用赶上,否则你不可能得到正确的dynamictypes的对象。 至于其寿命,标准保证,在[except.throw]
,
exception对象在exception的最后剩余活动处理程序以重新抛出之外的任何方式退出之后被销毁,或者引用exception对象的typesstd :: exception_ptr(18.8.5)的最后一个对象被销毁,以较晚者为准
通过const引用来捕获exception是应该如何捕获的。 exception对象不一定生活在“堆栈”上。 编译器负责使这个工作适当的魔术。
另一方面,你的例子不能编译,因为std::exception
只能是默认构造或复制构造的。 在这种情况下, what()
方法将返回一个指向空(c-style)string的指针,这不是特别有用。
build议您根据需要std::logic_error
std::runtime_error
或std::logic_error
,或从中派生一个类:
- 当调用者请求服务的devise参数外的
logic_error
。 -
runtime_error
时错误,当调用者请求合理的东西,但外部因素阻止你履行请求。
从except.throw :
抛出exception拷贝 – 初始化(8.5,12.8)临时对象,称为exception对象。 临时值是一个左值,用于初始化匹配处理程序(15.3)中声明的variables。 如果exception对象的types是一个不完整的types或指向除(可能是cv-qualified)无效的不完整types的指针,则该程序是格式不正确的。
这是抛出exception的行为,将exception对象复制到exception区域之外的任何堆栈之外。 因此,通过引用来捕获exception是完全合法的,并且是可取的,因为exception对象的生存期将延长到最后可能的catch()
。