在修改的exception上使用`throw;`

我有一个函数foo可以抛出一个exception。

在另一个函数中,我调用foo但是如果抛出exception,我可以添加一些更多的细节。 (我宁愿不将这样的信息作为parameter passing给foo因为它不属于那个属性,因为这个函数的generics特性。)

所以我在调用者中这样做:

 try { foo(); } catch (bar& ex){ ex.addSomeMoreInformation(...); throw; } 

throw重新抛出修改的exception还是我需要使用throw ex; ? 后者大概会采取价值副本,所以我宁愿不这样做。 会throw一个有价值的副本吗? 我怀疑它不会。

(我知道我可以validation,但我担心绊倒一个未指定或未定义的结构,所以想知道肯定)。

C ++ 11§15.1/ 8:

没有操作数的throw-expression会重新抛出当前处理的exception(15.3)。 该例外与现有的临时性重新激活; 没有新的临时exception对象被创build。

其实这里的标准很精确 [except.handle] / 17:

当处理程序声明对非常量对象的引用时,对引用对象的任何更改都是对执行throw-expression时初始化的临时对象的更改,如果该对象被重新抛出 ,将会产生影响

和[except.throw] / 8:

没有操作数的throw-expression会重新抛出当前处理的exception(15.3)。

在这种情况下,您应该使用throw来获得所需的行为…即抛出抛出修改的exception作为例外被引用捕获。

让我试着在这些之间做出区分,通过例子展示:

 class exception { }; class MyException : public exception { }; void func() { try { throw MyException(); } catch( exception& e ) { //do some modification. throw; //Statement_1 throw e; //Statement_2 } } 

Statment_1: –

抛出什么东西只是重新抛出当前的exception,即不会进一步复制(如最初抛出exception时所做的那样)。 所以,如果你在这里对抓到的exception做任何修改,它也会在调用程序中。

Statement_2: –

这是抛出最初被捕获为MyException的“exception”,即它会再次复制。 所以,只要忘记你所做的更改,甚至不会传递给调用者。 它向调用程序抛出“exception”。

希望我清楚(和正确的C ++标准跟踪)足够…

throw (没有exception对象)将重新抛出当前exception。 (必须在catch块内,否则调用std :: terminate )。 因为您更改了当前exception对象的引用,所以不需要明确地抛出对象并抛出修改的exception ,也不会创build新的临时对象。

根据这个 ,在c ++中抛出exception可以通过两种方式来完成:

  1. 抛出 expression式 :首先,从expression式中复制 – 初始化exception对象(这可能会调用rvalueexpression式的移动构造函数,并且复制/移动可能会受到复制的影响),然后将控制权转移给exception处理程序,语句或成员初始化程序列表是最近input的,不会由此执行线程退出。
  2. 抛出 :重新绘制当前处理的exception。 放弃当前catch块的执行,并将控制权传递给下一个匹配的exception处理程序(但不包括同一个try块之后的另一个catch子句:它的compound-statement被认为已经“退出”了),重用现有的exception对象:没有新的对象。 只有在目前正在处理exception的情况下才允许使用这种forms(如果使用其他方式,则调用std :: terminate)。 如果在构造函数中使用,则与函数尝试块关联的catch子句必须通过重新抛出来退出。

所以强调我的答案, 在你的情况应该罚款。