Qt5新信号到lambda连接内存泄漏

Sig*_*gil 22 c++ signals slot c++11 qt5

新的Qt5信号和插槽语法使我们不仅可以将信号连接到插槽,还可以连接普通旧功能和仿函数/ lambda.现在的问题是,lambdas是带有()运算符的必要对象,当你将信号连接到它们时,它们会被复制到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
Run Code Online (Sandbox Code Playgroud)

现在,当我在插槽断开后查看连接变量的强引用计数时,它会保持2,这意味着仿函数对象本身仍然存活且很好,尽管现在对我没用.我错过了什么吗?

pep*_*ppe 9

这个例子是过度设计的(为什么要使用QSharedPointer?为什么要按捕获?).但实际上Qt正在泄漏仿函数对象.

关键是内部连接列表只是标记为脏,并且在删除发送方或连接新信号之前不会清除(请参阅cleanConnectionLists的用法).

我推了几个应该解决这个问题的补丁:https://codereview.qt-project.org/#change,42976和42979

  • 嗯,是的,我知道它可能看起来有点过度设计,但我需要那个共享指针只是为了能够轻松监控对它的引用数量,看看函子对象是否还活着,而且我确实有一个真正的类似逻辑不在 main 函数内部的项目,所以我不能只通过引用来捕获连接。 (2认同)