Qt插槽和小型转储



我们在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没有得到。无论如何,至少,您可以弄清楚发生了什么,例如,什么类型的事件处理程序向什么类型的对象中抛出。

最新更新