Qt 捕获应用程序未知异常的方法
Qt 官方强烈建议在事件处理函数(如槽函数、事件过滤器)内部就地处理异常,而不是依赖全局捕获来恢复程序
1. 针对信号与槽的全局捕获(推荐)
从 Qt 5.x 开始,如果槽函数抛出了未被捕获的异常,Qt 会通过QCoreApplication发出unhandledException信号。这是官方推荐的处理此类异常的方式。
#include <QCoreApplication> #include <QDebug> #include <QUnhandledException> void handleUnhandledException(QUnhandledException e) { try { // 重新抛出保存的异常以获取具体类型 std::rethrow_exception(e.exception()); } catch (const std::exception& ex) { qCritical() << "捕获到未处理异常:" << ex.what(); } catch (...) { qCritical() << "捕获到未知未处理异常!"; } } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); // 连接全局未处理异常信号 QObject::connect(&app, &QCoreApplication::unhandledException, handleUnhandledException); // ... 其他代码 return app.exec(); }2. 重写 QApplication 的 notify 函数
notify负责分发所有事件。通过在重写的方法中添加try-catch块,可以捕获事件分发过程中抛出的所有 C++ 异常。
class MyApplication : public QApplication { public: MyApplication(int& argc, char** argv) : QApplication(argc, argv) {} virtual bool notify(QObject* receiver, QEvent* event) override { try { return QApplication::notify(receiver, event); } catch (const std::exception& e) { qCritical() << "事件分发中捕获异常:" << e.what(); // 此处通常不建议尝试恢复程序,建议执行清理后退出 return false; } } }; int main(int argc, char** argv) { MyApplication app(argc, argv); // ... return app.exec(); }3. 针对 Qt Concurrent 的线程异常
在使用QtConcurrent进行多线程编程时,如果工作线程抛出了非QException子类的异常,接收线程会捕获到一个QUnhandledException,可以通过它拿到原始异常。
try { auto future = QtConcurrent::run([] { throw std::runtime_error("thread error"); }); future.waitForFinished(); } catch (const QUnhandledException& e) { if (e.exception()) { try { std::rethrow_exception(e.exception()); } catch (const std::exception& ex) { qDebug() << "线程异常:" << ex.what(); } } }4. 全局消息处理(非异常,用于崩溃日志)
如果你想捕获的是segfault或除零等导致程序崩溃的系统级错误(而非 C++ 异常),可以安装一个消息处理函数。但这主要用于记录日志后安全退出,无法真正“恢复”程序。
void myMessageHandler(QtMsgType type, const QMessageLogContext&, const QString& msg) { if (type == QtFatalMsg) { // 记录崩溃日志 } } int main() { qInstallMessageHandler(myMessageHandler); // ... }重要说明
无法恢复:上述方法主要目的是在程序结束前记录错误或执行清理。根据 Qt 开发组的意见,不允许异常穿透 Qt 的事件循环,因为一旦信号/槽链中的异常未被就地捕获,程序状态可能已不一致,最安全的做法是终止程序。
Windows SEH 异常:在 Windows 上,访问违例等系统级异常(SEH)与 C++ 异常机制不同。虽然 Qt 内部有处理,但标准的
try-catch通常无法捕获,需要依赖上述的qInstallMessageHandler或 Windows 特定的结构化异常处理。
