异常安全性
预先警告:异常安全性功能尚未完全完善!常见情况应该可以正常工作,但类可能仍然会泄漏或甚至崩溃。
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
也会返回一个有效的指针。
在其他所有操作系统上,如果任何分配失败,Qt 将抛出一个类型为 std::bad_alloc 的异常。如果系统内存不足或没有足够的连续内存来分配请求的大小,则分配可能失败。
违反该规则的例外情况进行了记录。例如,如果 QImage 构造函数在没有足够的内存的情况下,将创建一个空的图像而不是抛出异常。
从异常中恢复
目前,从 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;
在抛出异常之后,与窗口服务器的连接可能已经关闭。在捕获异常后调用与 GUI 相关的函数是不安全的。
客户端代码中的异常
信号和槽
从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. stateListener.throwException(); } catch (...) { qDebug() << "Handling exception not caught in slot."; }
© 2024 The Qt Company Ltd. 本文档中包含的文档贡献权属于其各自的所有者。本文档是根据由自由软件基金会发布的GNU自由文档许可证1.3版许可的。Qt及其相应标志是芬兰以及全球其他国家的The Qt Company Ltd.的商标。所有其他商标均为其各自所有者的财产。