2013-02-12 3 views
20

Czy można odłączyć funkcję lambda? A jeśli "tak", w jaki sposób?Odłączanie funkcji lambda w Qt5

Według https://qt-project.org/wiki/New_Signal_Slot_Syntax potrzebuję użyć QMetaObject::Connection, który jest zwracany z metody QObject :: connect, ale jak mogę przekazać ten obiekt do funkcji lambda?

przykład Pseudo-kod:

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

Czy próbowałeś tego? (Ale także dodaj 'conn' do listy przechwytywania dla lambda) –

+0

@JoachimPileborg Tak, to z jakiegoś powodu kruszywo. Jak tylko usunę połączenie QMetaObject :: Connection i zostawię tylko kod po tym, jak = zniknie błąd segfault. – alexandernst

+2

Problem jest omawiany tutaj: http://stackoverflow.com/questions/13847507/qt5-new-signal-to-lambda-connections-memory-leak – kfunk

Odpowiedz

23

Jeśli uchwycić conn bezpośrednio, jesteś zrobieniem zainicjalizowana obiektu poprzez kopiowanie, co powoduje zachowanie niezdefiniowane. Trzeba uchwycić inteligentnego wskaźnika:

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

lub przy użyciu udostępnionego wskaźnik, z nieco większym obciążeniu:

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

Od Qt 5.2 można zamiast tego użyć obiektu kontekstowego:

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

Czy możesz wyjaśnić dokładniej ten pierwszy przykład? Dlaczego tworzysz wskaźnik, a następnie odwołujesz się do wskaźnika i przekazujesz oba do lambda? Edycja: Nie można zrobić czegoś takiego: * pconn = QObject :: connect (...); koniec całkowicie wyjść z conn? – stepanbujnak

+0

W pierwszym przykładzie żywotność 'conn' jest określona przez blok kodu, podczas gdy funkcja lambda nadal go używa. Szczęście, jeśli "conn" wciąż żyje. W tym scenariuszu zdecydowanie potrzebujesz 'shared_ptr '. – xtofl

+0

@xtofl 'conn' w pierwszym przykładzie jest odniesieniem; jego żywotność jest czasem życia 'unique_ptr', który jest przechwytywany do lambda. (Powinien to być proces przechwytywania init w C++ 14). – ecatmur