异常安全
初步警告:异常安全功能并不完善!常见情况下应该可以正常工作,但类仍然可能泄漏或甚至崩溃。
Qt 本身不会抛出异常。相反,Qt 会使用错误代码。此外,有些类有用户可见的错误信息,例如QIODevice::errorString() 或QSqlQuery::lastError() 。这既有历史原因,也有现实原因--开启异常会使库的大小增加 20% 以上。
下面几节将描述 Qt 在编译时启用异常支持时的行为。
异常安全模块
容器
Qt 的容器类通常是异常中立的。它们会将其包含的类型T
中发生的任何异常传递给用户,同时保持其内部状态有效。
例如
QList<QString> list; ... try { list.append("hello"); } catch (...) { } // list is safe to use - the exception did not affect it.
该规则的例外情况是在赋值或复制结构中可能抛出异常的类型的容器。对于这些类型,使用修改容器和返回值的函数是不安全的:
MyType s = list.takeAt(2);
如果在s
的赋值过程中出现异常,索引 2 处的值已经从容器中删除,但尚未赋值给s
。这个值就会丢失,没有恢复的可能。
正确的写法是
MyType s = list.at(2); list.removeAt(2);
如果赋值失败,容器中仍将包含值;数据不会丢失。
请注意,隐式共享的 Qt 类不会抛出赋值操作符或复制构造函数,因此上述限制并不适用。
内存不足处理
大多数桌面操作系统都会超量使用内存。这意味着malloc()
或operator new
会返回一个有效指针,即使在分配时没有足够的可用内存。在这种系统中,不会抛出std::bad_alloc
类型的异常。
在所有其他操作系统上,如果分配失败,Qt 将抛出 std::bad_alloc 类型的异常。如果系统内存耗尽或没有足够的连续内存来分配所请求的大小,分配就会失败。
该规则的例外情况已记录在案。例如,如果内存不足,QImage 构造函数将创建一个null 镜像,而不是抛出异常。
从异常中恢复
目前,从 Qt 中抛出的异常(例如由于内存不足)中恢复的唯一支持用例是退出事件循环,并在退出应用程序前进行一些清理。
典型用例:
QApplication app(argc, argv); ... int ret; try { ret = app.exec(); } catch (const std::bad_alloc &) { // clean up here, e.g. save the session // and close all config files. return EXIT_FAILURE; // exit the application } ... return ret;
抛出异常后,与窗口服务器的连接可能已经关闭。在捕获异常后调用与图形用户界面相关的函数并不安全。
客户端代码中的异常
信号和插槽
从 Qt 的信号槽连接机制调用的槽中抛出异常被视为未定义的行为,除非在槽中进行了处理:
State state; StateListener stateListener; // OK; the exception is handled before it leaves the slot. QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwHandledException())); // Undefined behaviour; upon invocation of the slot, the exception will be propagated to the // point of emission, unwinding the stack of the Qt code (which is not guaranteed to be exception safe). QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwUnhandledException()));
如果槽是直接调用的,就像普通函数调用一样,则可以使用异常。这是因为直接调用插槽时绕过了连接机制:
State state; StateListener stateListener;// ...try{// OK; invoking slot directly. qDebug() << "Handling exception not caught in slot."; }
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.