我们在windows上用Qt
编写了一个小程序,我们使用minidump
来帮助我们捕获客户端崩溃。我们的目标是至少在调用堆栈崩溃时查看它。
...
SetUnhandledExceptionFilter(unhandled_handler); // write minidump in unhandled_handler
...
问题是它并不总是在崩溃后创建小型转储,有时错误日志会显示:
Warning: Qt has caught an exception thrown from an event handler. Throwing
exceptions from an event handler is not supported in Qt. You must
reimplement QApplication::notify() and catch all exceptions there.
qt是否捕捉到异常并停止我的应用程序创建小型转储?
有时我们也会得到无用的小型转储结果,它的调用堆栈是:
[Frames may be missing, no binary loaded for KERNELBASE.dll]
KERNELBASE.dll!00007ffd05bd4fd9() Unknown
带输出
Unhandled exception at 0x00007FFD05BD4FD9 in SofterClear_1_22_0_220822_141118_061915.dmp: Microsoft C++ exception: std::
据此:
Throwing an exception from a slot invoked by Qt's signal-slot connection mechanism is considered undefined behaviour, unless it is handled within the slot
我已尝试将QApplication::notify
覆盖为
bool AlignApplication::notify(QObject * receiver, QEvent * event)
{
bool done = true;
try {
done = QApplication:
}
catch (const std::exception& ex) {
throw ex; // I have also tried to create minidump here, but it's empty and useless.
}
catch (...) {
throw "unknown error";
}
return done;
但它不起作用。
在Qt插槽中发生异常后,是否可以创建具有完整调用堆栈的小型转储?
为了让事情更清楚一点,这是一个被重写的QApplication::notify
:的典型实现
bool TestApp::notify(QObject * object, QEvent * event)
{
try {
return QApplication::notify(object, event);
}
catch(...) {
// you can do something here, but can't rethrow
}
}
如果你重新思考呢?好吧,猜测一下:notify
是一个事件处理程序,所以你很可能会得到一个矛盾地建议覆盖notify
的警告。。。
现在,关于在接球区做其他事情,让我们首先了解投球发生在哪里。我们知道:在父对象的notify
中,所以在事件传递的中间,很可能在接收对象的事件处理程序中。
所以,我会尝试一件简单的事情,就是在捕捉块中放一条像这样的线
qDebug() << object->metaObject()->className() << " <= " << event->type();
只是为了弄清楚在处理什么样的事件时抛出了什么样的对象。
在异步Qt风格中应该做的任何其他事情,即发布一个事件,该事件稍后将被调度(无论如何,在notify
返回之后(。假设您想退出应用程序:
QMetaObject::invokeMethod(this, "quit");
并且紧接着返回CCD_ 9或CCD_。
现在回答您的问题:
qt是否捕获异常并停止我的应用程序创建小型转储?
不,您可以像往常一样捕获所有东西,但如果您想捕获从事件处理程序抛出的异常,您必须覆盖上面的"notify"方法。
是否可以在Qt插槽中发生异常?
如果直接调用插槽(例如使用Qt::DirectConnection
连接(,那么肯定是的。您可以在try块中发出调用信号,并捕获插槽抛出的任何东西:
try {
emit some_signal();
}
catch(...) {
// the slot threw something ...
}
另一方面,如果插槽调用中涉及事件循环(例如,使用Qt::QueuedConnection
连接(,我会再次回答"是",这里有两个选项:
- 尝试在槽内接球(不要投球(
notify
中的catch,如上所述
但是,在第二种情况下,你说你没有得到完整的调用堆栈,我真的不能说它是什么,但我很确定你不能责怪Qt没有得到。无论如何,至少,您可以弄清楚发生了什么,例如,什么类型的事件处理程序向什么类型的对象中抛出。