从catch块重新抛出异常时丢失异常类型

Lor*_*one 14 c++ exception try-catch

今天我在一个catch块中发现了一个错误:

catch (const exception& e){
    // do something
    // throw e; <-- bug!
    throw;    // <-- right thing to do
}
Run Code Online (Sandbox Code Playgroud)

基本上,如果我e 明确地重新抛出异常,我会得到一个新的std::exception重构,实际上该what()方法的消息是默认的std::string,而不是我的自定义构建的消息.

解释是什么?我认为这throw;只是一个简写throw ExceptionJustCaught;.

Ker*_* SB 14

异常对象有点特殊.它们是在记忆中的特殊位置构建的,它们的生命周期取决于它们被捕获的捕获块.

如果你说throw e;,原始异常的生命周期在catch块的末尾结束,并且你通过复制抛出一个新的异常e,从而产生一个经典的切片问题:因为它e是一个多态的引用,它的动态类型通常更多- 结果std::exception,你最终切掉对象的派生部分.

与此相反,throw;是重新激活原来的异常,因此它不再抓住,它的寿命也特别声明不是在块的结束而终止了.实际上,如果您通过非常量引用捕获,则可以继续修改异常对象并重新抛出,从而将较低的catch块通知状态更改.但请记住,重新抛出与抛出新的异常不同!


Dav*_*rtz 8

只是throw通过引用抛出当前异常.throw ecopy构造一个新的异常抛出.这与工作方式大致相同return.