std :: rethrow_exception和抛出的异常类型

时间:2016-05-16 08:32:29

标签: c++ c++11

在库中,我有一个例外层次结构(RuntimeException -> RecognitionException -> NoViableAltException)。在执行期间,抛出NoViableAltException,如下所示,并从中创建异常指针:

try {
   //code that throws NoViableAltException
} catch (RecognitionException &re) {
  std::exception_ptr e = std::make_exception_ptr(re);
  reportError(e);
}

e的值在其他地方使用,与此问题无关。在reportError()我实际上处理了错误:

void reportError(std::exception_ptr e) {
...
  try {
    std::rethrow_exception(e);
  } catch (NoViableAltException &ne) {
    reportNoViableAlternative(recognizer, ne);
  } catch (InputMismatchException &ne) {
    reportInputMismatch(recognizer, ne);
  } catch (FailedPredicateException &ne) {
    reportFailedPredicate(recognizer, ne);
  } catch (RecognitionException &ne) {
    recognizer->notifyErrorListeners(ne.getOffendingToken(), ne.what(), e);
  }
}

这是我的问题:当我重新提出e时,NoViableAltException分支不会被采用,而是RecognitionException(最后一个)的分支。这是令人惊讶的,我想知道为什么会这样。我也试图抓住NoViableAltException*,但没有用。捕获各个异常类型的正确方法是什么?

2 个答案:

答案 0 :(得分:14)

不要使用make_exception_ptr;这是不同的东西(它使用推导的异常类型创建一个 new 异常指针,并且您的代码最终会切割捕获的异常对象)。相反,您想要捕获current exception

catch (RecognitionException &)
{
     std::exception_ptr e = std::current_exception();
     // ...
}

答案 1 :(得分:8)

来自documentation for std::make_exception_ptr

  

创建一个std :: exception_ptr,其中包含对e。

副本的引用

不幸的是,复制 e意味着你得到了对象切片(@Mohamad Elghawi指出,该页面后面也会更加突出地提到)。当您致电std::make_exception_ptr<RecognitionException>时,它会保留RecognitionException的副本,而不是任何派生类。

但你在这里根本不需要exception_ptr。即使reportError在范围内没有try ... catch,您仍然可以使用throw;重新抛出当前异常。

#include <stdio.h>

struct A { virtual ~A() = default; };
struct B : A { };

void reportError() {
  try {
    throw;
  }
  catch (B &) {
    puts("caught B");
  }
  catch (A &) {
    puts("caught A");
  }
}

int main() {
  try {
    throw B();
  }
  catch (A &) {
    reportError();
  }
}