The context object is used in two scenarios.
Auto shut off
Let me first take a step back and ask myself: when does Qt break the connection?
With a normal connection, connect(sender, signal, receiver, slot) there are three possibilities:
- When someone explicitly calls
disconnect ; - When
sender removed, - If the
receiver deleted.
Especially in cases No. 2 and No. 3, for Qt it makes sense to behave in this way (in fact, it should behave in this way, otherwise you will have resource leaks and / or crashes).
Now: when using connect overload using a functor, when does Qt break the connection?
Note that without the context parameter, there is only one QObject: the sender. Therefore, the answer is:
- When someone explicitly calls
disconnect ; - If
sender removed.
Of course, there is no recipient object! Thus, only the sender automatically controls the lifetime of the connection.
Now the problem is that the functor may capture some additional state, which may become invalid, in which case it is desirable that the connection be damaged automatically. Typical case: lambdas:
connect(sender, &Sender::signal, [&object1, &object2](Param p) { use(object1, object2, p); } );
What happens if object1 or object2 deleted? The connection will still be alive, so the radiation of the signal will still cause a lambda, which, in turn, will have access to the destroyed objects. And that's bad...
For this reason, when it comes to functors, connect overloading was introduced using a context object . A connection established using this overload will be automatically disconnected.
- when the
context object is deleted.
You are probably right when you say that many times you will see there the very βmainβ object that is used in the functor, for example
connect(button, &QPushButton::clicked, otherWidget, [otherWidget]() { otherWidget->doThis(); otherWidget->doThat(); } );
It's just a template in Qt - when setting up connections for sub-objects, you usually connect them to the slots on the this object, so this is probably the most common context. However, in general, you can also get something like
// manages the lifetime of the resources; they will never outlive this object struct ResourceManager : QObject { Resource res1; // non-QObjects OtherResource res2; }; ResourceManager manager; connect(sender, signal, manager, [&manager](){ use(manager.res1, ...); }); // or, directly capture the resources, not the handle
So, you are capturing part of the manager state.
In the most general case, when the context object is available, if there is a chance that the objects captured by the lambda will exit the connection, then you should grab them with weak pointers and try to lock these pointers inside the lambda before trying to access them.
Running a functor in a specific thread / event chain
Very soon: when specifying a context object, the functor will be launched in the context stream , as well as regular connections using the recipient object. Note that the overload of connect , which accepts the context, also accepts the type of connection (while one without a context does not accept one connection always always).
Again, this is useful because QObject is not reentrant or thread safe, and you should use QObject only in the stream in which it lives. If your functor accesses an object living in another thread, it must be executed in this thread; indicating that the object in the context solves the problem.