当 Qt-5 连接失败时

Posted

技术标签:

【中文标题】当 Qt-5 连接失败时【英文标题】:When Qt-5 will fail the connect 【发布时间】:2017-04-19 06:12:15 【问题描述】:

阅读Qt signal & slots documentation,似乎新样式连接失败的唯一原因是: “如果已经存在重复(完全相同的信号到同一对象上完全相同的插槽),则连接将失败并且连接将返回 false”

表示第一次连接已经成功,使用Qt::UniqueConnection时不允许多连接。

这是否意味着 Qt-5 风格的连接总是会成功?还有其他失败的原因吗?

【问题讨论】:

【参考方案1】:

新样式的connect 在运行时仍然可能由于各种原因而失败:

senderreceiver 是空指针。显然,这需要一个只能在运行时进行的检查。

您为信号指定的 PMF 实际上并不是信号。由于缺乏适当的 C++ 反射功能,您在编译时所能做的就是检查信号是否是发送方类的非静态成员函数。

但是,这还不足以使它成为一个信号:它还需要在您的类定义中的 signals: 部分中。当moc 看到您的类定义时,它将生成some metadata,其中包含该函数确实是一个信号的信息。因此,在运行时,传递给connect 的指针会在表中查找,如果找不到指针,connect 本身就会失败(因为您没有传递信号)。

上一点的检查其实需要比较成员函数的指针。这是一个特别棘手的问题,因为它通常会涉及不同的 TU:

    一个是包含 moc 生成数据的 TU(通常是 moc_class.cpp 文件)。在这个 TU 中有上述表格,其中包含指向信号的指针(这些只是普通的成员函数)。 是您实际调用 connect(sender, &Sender::signal, ...) 的 TU,它会生成在表中查找的指针。

现在,两个 TU 可能在同一个应用程序中,或者一个在一个库中,另一个在您的应用程序中,或者可能在两个库中,等等;您平台的ABI 开始发挥作用。

理论上,做 1. 时存储的指针与做 2. 时生成的指针是相同的;在实践中,我们发现了这种情况不会发生的情况(参见我前段时间报告的 bug report,其中 ARM 上的旧版本 GNU ld 生成的代码比较失败)。

对于 Qt,这意味着禁用某些优化和/或将一些额外的标志传递到我们知道会发生这种情况并破坏用户软件的地方。例如,从 Qt 5.9 开始,除了 x86 和 x86-64 之外,GCC 上不支持 -Bsymbolic* 标志。

当然,这并不意味着我们已经找到并修复了所有可能的位置。新的编译器和更积极的优化可能会在未来再次触发此错误,使 connect 返回 false,即使一切都应该工作。

【讨论】:

【参考方案2】:

是的,如果发送者或接收者不是有效对象(例如 nullptr),它可能会失败

例子

QObject* obj1 = new QObject();
QObject* obj2 = new QObject();
// Will succeed
connect(obj1, &QObject::destroyed, obj2, &QObject::deleteLater);
delete obj1;
obj1 = nullptr;
// Will fail even if it compiles
connect(obj1, &QObject::destroyed, obj2, &QObject::deleteLater);

【讨论】:

【参考方案3】:

不,它并不总是成功的。文档给出了一个示例 here,其中 connect 将返回 false,因为信号不应包含变量名。

// WRONG
QObject::connect(scrollBar, SIGNAL(valueChanged(int value)),
             label, SLOT(setNum(int value)));

【讨论】:

这不是 Qt5 风格的连接

以上是关于当 Qt-5 连接失败时的主要内容,如果未能解决你的问题,请参考以下文章

当 InternetOpenURL 尝试(并且失败)连接时,如何避免充分利用 CPU 或终止?

浏览器在请求失败时自行发出请求,当互联网重新连接时

当前缀字符串与非前缀字符串相邻时,字符串文字连接失败?

与 Facebook 聊天连接时远程连接失败

回调中的 RMI 连接失败检测

nginx:连接到上游时连接()失败(111:连接被拒绝)