2013-02-12 112 views
20

是否可以斷開lambda函數?如果「是」,如何?斷開Qt5中的lambda函數

根據https://qt-project.org/wiki/New_Signal_Slot_Syntax我需要使用從QObject :: connect方法返回的QMetaObject::Connection,但我怎樣才能將該對象傳遞給lambda函數?

僞代碼示例:

QMetaObject::Connection conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [this](){ 
    QObject::disconnect(conn); //<---- Won't work because conn isn't captured 

    //do some stuff with sock, like sock->readAll(); 
} 
+0

你嘗試過嗎? (但是也可以將'conn'添加到lambda的捕獲列表中) – 2013-02-12 08:51:28

+0

@JoachimPileborg是的,它由於某種原因發生段錯誤。只要我刪除了QMetaObject :: Connection conn,並且只保留了= segmentation消失後的代碼。 – alexandernst 2013-02-12 08:52:47

+2

這個問題在這裏討論:http://stackoverflow.com/questions/13847507/qt5-new-signal-to-lambda-connections-memory-leak – kfunk 2013-02-12 09:33:25

回答

23

如果直接捕捉conn,你捕獲通過複製一個未初始化的對象,這會導致不確定的行爲。您需要捕獲一個智能指針:

std::unique_ptr<QMetaObject::Connection> pconn{new QMetaObject::Connection}; 
QMetaObject::Connection &conn = *pconn; 
conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [this, pconn, &conn](){ 
    QObject::disconnect(conn); 
    // ... 
} 

或使用共享指針,與稍大的開銷:

auto conn = std::make_shared<QMetaObject::Connection>(); 
*conn = QObject::connect(m_sock, &QLocalSocket::readyRead, [this, conn](){ 
    QObject::disconnect(*conn); 
    // ... 
} 

從Qt的5.2你也可以使用一個上下文對象:

std::unique_ptr<QObject> context{new QObject}; 
QObject* pcontext = context.get(); 
QObject::connect(m_sock, &QLocalSocket::readyRead, pcontext, 
    [this, context = std::move(context)]() mutable { 
    context.clear(); 
     // ... 
    }); 
+1

您能否詳細解釋第一個例子?爲什麼你要創建指針,然後引用指針並傳遞給lambda? 編輯: 是不是可以做這樣的事情: * pconn = QObject :: connect(...); 結束離開conn完全離開它嗎? – stepanbujnak 2013-07-06 15:59:46

+0

在第一個例子中,'conn'的生命週期由代碼塊決定,而lambda函數仍然使用它。如果'conn'還活着,那麼運氣真好。在這種情況下,你肯定需要'shared_ptr '。 – xtofl 2015-02-06 08:18:07

+0

@xtofl'conn'在第一個例子中是一個引用;它的生命週期是'unique_ptr'的生命週期,它被捕獲到lambda中。 (這應該是一個C++ 14初始化捕獲,真的。) – ecatmur 2015-02-06 21:33:12