在库中,我有一个例外层次结构(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*
,但没有用。捕获各个异常类型的正确方法是什么?
答案 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();
}
}