2012-12-12 57 views
19

新的Qt5信號和插槽語法使我們不僅可以將信號連接到插槽,還可以連接到普通的舊功能和仿函數/ lambdas。現在的問題是,lambda是帶有()運算符的基本對象,當你連接信號給它們時,它們會被複制到qt內部類的某個地方。而且,當你斷開該仿函數的信號時,它保持在qt內部。我不明白,這是一種正常的行爲?或者也許有辦法在斷開連接後銷燬這些功能對象?Qt5新信號到lambda連接內存泄漏

下面是一個例子:

//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,這意味着仿函數對象本身仍然活得很好,雖然它現在對我來說毫無用處。我想念什麼?

+0

會發生什麼事,當你破壞了計時器? –

+0

也有這樣的想法,但引用計數仍然保持2 =/ – Sigil

+0

如果我不在該*'connection.data()='部分中存儲連接變量並刪除該計時器,則唯一方法是1。這仍然很奇怪。 – Sigil

回答

7

該示例過度設計(爲什麼使用QSharedPointer?爲什麼要通過值捕獲它?)。但的確Qt泄漏了函數對象。

問題是內部連接列表被簡單地標記爲髒,並且直到發送者被刪除或連接了一個新信號(見cleanConnectionLists的用法)才被清除。

我推了幾個補丁應該解決這個行爲:https://codereview.qt-project.org/#change,42976和42979

+1

嗯,我知道它可能看起來有些過度設計,但我需要這個共享指針只是爲了能夠輕鬆地監視引用的數量,查看仿函數對象是否還活着,而且我確實有一個真正的項目中,類似的邏輯不在主函數內部,所以我不能僅僅通過引用來捕獲連接。 – Sigil