Qt5新的信号与lambda连接存在内存泄漏问题

24
新的Qt5信号和槽语法使我们不仅可以将信号连接到槽,还可以连接到普通函数和函数对象/lambda。现在问题是,lambda本质上是带有()运算符的对象,当您将信号连接到它们时,它们会被复制到qt内部类的某个位置。而且,当您从该函数对象断开信号时,它会留在qt内部。我不明白这是否是正常行为?或者也许有一种方法可以在断开连接后销毁这些函数对象吗?
以下是示例:
//example

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QTimer* timer = new QTimer();

    QSharedPointer<QMetaObject::Connection> connection(new QMetaObject::Connection());

    //functor is created and gets copied inside qt internals, connection variable is captured
    //inside the functor

    *connection.data() = QObject::connect(timer, &QTimer::timeout, [=]
    {
        qDebug() << "disconnected";
        QObject::disconnect(*connection.data());
    });

    timer->start(10000);

    return a.exec();
}

//example

现在,当我在插槽断开连接后查看连接变量的强引用计数时,它仍然保持为2,这意味着函数对象本身仍然存在并正常运行,尽管对我来说已经没有用处了。我有什么遗漏吗?


当你销毁计时器时会发生什么? - Reuben Morais
也曾有过这样的想法,但是引用计数仍然保持为2 =/ - Sigil
只有当我不在那个“*connection.data() =”部分存储连接变量并删除计时器时,它才会变成1。这仍然非常奇怪。 - Sigil
жҲ‘е·Із»ҸжңүдёҖж®өж—¶й—ҙжІЎжңүдҪҝз”ЁQtдәҶпјҢдҪҶжҳҜдҪ дёҚиғҪдҪҝз”Ёиҝ”еӣһзҡ„QMetaObject::ConnectionдҪҝз”ЁзӣёеҗҢзҡ„еҸӮж•°йҮҚж–°иҝһжҺҘеҗ—пјҹиҝҷеҸҜд»Ҙи§ЈйҮҠдёәд»Җд№Ҳе®ғдҝқз•ҷеҜ№иҜҘеҮҪж•°зҡ„еј•з”ЁгҖӮ - Reuben Morais
1
我认为没有重新连接的方法。从源代码来看,disconnect()将接收器设置为0。因此,无法恢复连接。我认为OP确实发现了内存泄漏问题。请提交错误报告。 - Stephen Chu
1个回答

10
这个例子被过度设计了(为什么要使用QSharedPointer?为什么以值传递方式捕获它?)。但确实Qt正在泄漏函数对象。
重点是内部连接列表只是被标记为脏的,并且直到发送者被删除或新信号连接时才清除(请参见cleanConnectionLists的用法)。
我推送了一些补丁,应该可以解决这个问题:https://codereview.qt-project.org/#change,42976和42979。

2
嗯,我知道这看起来可能有点过度设计,但我需要那个共享指针,只是为了能够轻松地监视对它的引用数量,以查看函数对象是否仍然存在。我确实有一个真正的项目,其中类似的逻辑不在主函数内部,因此我不能在那里通过引用捕获连接。 - Sigil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接