2013-02-12 14 views
20

È possibile scollegare una funzione lambda? E se "si", come?Disconnessione delle funzioni lambda in Qt5

Secondo https://qt-project.org/wiki/New_Signal_Slot_Syntax Ho bisogno di usare un QMetaObject::Connection che viene restituito dal metodo QObject :: connect, ma come posso passare tale oggetto alla funzione lambda?

pseudo-codice di esempio:

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

Hai provato? (Ma aggiungi anche 'conn' alla lista di cattura per il lambda) –

+0

@JoachimPileborg Sì, seg segna per qualche motivo. Non appena rimuovo la connessione QMetaObject :: Connection e lascia solo il codice dopo = il segfault scompare. – alexandernst

+2

Il problema è discusso qui: http://stackoverflow.com/questions/13847507/qt5-new-signal-to-lambda-connections-memory-leak – kfunk

risposta

23

Se si cattura conn direttamente, si sta catturando un oggetto Non inizializzato da copia, che si traduce in un comportamento indefinito. È necessario acquisire un puntatore intelligente:

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); 
    // ... 
} 

o utilizzando un puntatore condiviso, con un po 'più in alto:

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

Da Qt 5.2 si potrebbe invece utilizzare un oggetto di contesto:

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

Potresti spiegare il primo esempio in maggiore dettaglio? Perché create un puntatore, quindi fate riferimento al puntatore e passate entrambi al lambda? Modifica: Non è possibile fare qualcosa di simile: * pconn = QObject :: connect (...); fine lasciare completamente il conn da esso? – stepanbujnak

+0

Nel primo esempio, la durata di 'conn' è determinata dal blocco di codice, mentre la funzione lambda lo usa ancora. Pura fortuna se 'conn' è ancora vivo. In questo scenario, hai sicuramente bisogno di un 'shared_ptr '. – xtofl

+0

@xtofl 'conn' nel primo esempio è un riferimento; la sua vita è la vita del 'unique_ptr', che viene catturato nel lambda. (Questo dovrebbe essere un C++ 14 init-capture, davvero.) – ecatmur

Problemi correlati