Destroy the signal/slot connection when the slot receives the signal
-
@J-Hilk I'm trying to implement a single shot connection waiting for an asynchronous response from http server. I'm curious if the connection in your code will be cleared when it gets out of scope?
Should I do something like this instead:QMetaObject::Connection * const connection = new QMetaObject::Connection; *connection = connect(sender, &Sender::signal, [this, connection](){ QObject::disconnect(*connection); delete connection; });
-
@johnyang thats not needed, the framework manages the lambda internally. In this case the connection and lambda will be valid as long as the
sender
instance exists or disconnect was called.And stuff captured by lambdas does not go out of scope, as long as you don't explicitly capture by reference. As it makes its own copy.
-
There is also a single shot connection type...
-
@johnyang Is
Sender
a long lived object that sendssignal
multiple times?
If not it might not be necessary to disconnect from it, similar to how we usually connect a lambda toQNetworkReply::finished
without disconnecting after.
And like Christian just said there'sQt::SingleShotConnection
as parameter ofQObject::connect
since Qt 6.0 -
@GrecKo said in Destroy the signal/slot connection when the slot receives the signal:
Qt::SingleShotConnection as parameter of QObject::connect since Qt 6.0
Look at that!
-
@J-Hilk Unfortunately I'm still on Qt5 at the moment. I would love to get onto Qt6 soon. I have another question about using the disconnect approach. I have the following scenario:
QMetaObject::Connection * const connection = new QMetaObject::Connection; *connection = connect(sender, &Sender::signal, [this, connection](){ QObject::disconnect(*connection); delete connection; // Some function that also sends out Sender::signal Function(); });
Function() also sends out Sender::signal at the end. The above code seems to be working fine that the lambda function does not get triggered. However if I do the following, the lambda function does get triggered one more time (which is not what I want):
QMetaObject::Connection conn; conn = QObject::connect(sender, &Sender::signal, [=]() { // Disconnect the connection QObject::disconnect(conn); // Some function that also sends out Sender::signal Function(); });
Is it alright to do what I did in the code above?
-
@GrecKo Sender is a long lived object but I only want it to take place once for a logic reason. I am still on Qt5 at the moment so I can't use Qt::SingleShotConnection. However in my example code with unique pointer, is it a bad practice to reset context in the lambda function because it is owned by context?
QObject* pcontext = context.get(); connect(this, &SenderClass::send, pcontext, [this, context = std::move(context)] mutable { context.reset(); // do something when received the signal Function(); });
-
At the moment, the suggested code in https://www.kdab.com/single-shot-connections/ seems to work perfectly so far:
auto connection = std::make_unique<QMetaObject::Connection>(); auto connectionPtr = connection.get(); auto singleShot = [receiver, connection = std::move(connection)](parameters) { QObject::disconnect(*connection); receiver->slot(parameters); }; *connectionPtr = connect(sender, &Sender::signal, receiver, std::move(singleShot)));
-
This is my concern about the above:
int a = 5; int b = 6; auto connection = std::make_unique<QMetaObject::Connection>(); auto connectionPtr = connection.get(); auto singleShot = [a, b, connection = std::move(connection)](parameters) { QObject::disconnect(*connection); // Is the captured variable 'a' and 'b' still valid here? Or has this lambda been destroyed by // the call to disconnect and thus 'a' and 'b' is no longer valid? doSomethingWith(a, b); }; *connectionPtr = connect(sender, &Sender::signal, receiver, std::move(singleShot)));
If the latter is true, (i.e. calling disconnect results in the lambda being destroyed) then we can no longer assume 'a' and 'b' are valid values. This could result in doSomethingWith(a, b) crashing, or worse not crashing because something else has occupied the address space of 'a' or 'b' and no longer represents the original value.
What I am ultimately asking here is, when does the lambda get destroyed after a disconnect is called?