本页内容

异常安全

初步警告:异常安全功能尚未完全实现!常见情况应该可以正常工作,但类仍可能发生内存泄漏甚至导致程序崩溃。

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;

异常抛出后,与窗口服务器的连接可能已经关闭。在捕获异常后调用与 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{
    // 正常;直接调用槽函数。
    stateListener.throwException();
}catch(...) {
    qDebug() << "Handling exception not caught in slot.";
}

© 2026 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.