2013-02-12 46 views
20

Có thể ngắt kết nối chức năng lambda không? Và nếu "có", làm thế nào?Ngắt kết nối các chức năng lambda trong Qt5

Theo https://qt-project.org/wiki/New_Signal_Slot_Syntax Tôi cần sử dụng QMetaObject::Connection được trả về từ phương pháp kết nối QObject :: nhưng sau đó làm cách nào để chuyển đối tượng đó vào hàm lambda?

Pseudo-code ví dụ:

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

Bạn đã thử chưa (Nhưng cũng thêm 'conn' vào danh sách chụp cho lambda) –

+0

@JoachimPileborg Có, nó segfaults vì một lý do nào đó. Ngay sau khi tôi loại bỏ các kết nối QMetaObject :: conn và chỉ để lại mã sau khi segfault = segfault. – alexandernst

+2

Sự cố được thảo luận tại đây: http://stackoverflow.com/questions/13847507/qt5-new-signal-to-lambda-connections-memory-leak – kfunk

Trả lời

23

Nếu bạn chụp conn trực tiếp, bạn đang chụp một đối tượng uninitialised bằng cách sao chép, mà kết quả trong hành vi undefined. Bạn cần phải nắm bắt một con trỏ thông minh:

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

Hoặc sử dụng một con trỏ được chia sẻ, với chi phí hơi lớn hơn:

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

Từ Qt 5.2 bạn thay vì có thể sử dụng một đối tượng bối cảnh:

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

Bạn có thể giải thích ví dụ đầu tiên chi tiết hơn không? Tại sao bạn tạo con trỏ, sau đó tham chiếu đến con trỏ và truyền cả hai đến lambda? Chỉnh sửa: Không thể thực hiện điều gì đó như: * pconn = QObject :: connect (...); kết thúc rời khỏi conn hoàn toàn ra khỏi nó? – stepanbujnak

+0

Trong ví dụ đầu tiên, tuổi thọ của 'conn' được xác định bởi khối mã, trong khi hàm lambda vẫn sử dụng nó. Tuyệt may mắn nếu 'conn' vẫn còn sống. Trong trường hợp này, bạn chắc chắn cần một 'shared_ptr '. – xtofl

+0

@xtofl 'conn' trong ví dụ đầu tiên là tham chiếu; tuổi thọ của nó là thời gian tồn tại của 'unique_ptr', được ghi lại trong lambda. (Điều này nên là một C++ 14 init-capture, thực sự.) – ecatmur

Các vấn đề liên quan