{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreiagypgoaa572g3b5krqrnf5tavvnh6nsuii25cmtsdu22we3si6wq",
"uri": "at://did:plc:6dmfe46c76jjenq3kaxc5eds/app.bsky.feed.post/3mkchs2lhxtb2"
},
"path": "/2026/04/qt-no-contextless-connect/",
"publishedAt": "2026-04-24T13:49:04.000Z",
"site": "https://blog.broulik.de",
"tags": [
"thing to look out for",
"QT_ENABLE_STRICT_MODE_UP_TO"
],
"textContent": "As many long running projects, Qt too over the years has accumulated some APIs that in hindsight are deemed unsafe or sub-optimal. For example, Qt by default implicitly converts _const char*_ to _QString_. While that usually only incurs a runtime overhead, maybe encoding problems, but also admittedly less cluttered code, there’s other APIs that can backfire in more subtle ways. One such API is doing a “context-less connect”.\n\nSignals and Slots are a core principle of Qt that make it super easy to connect one object to another and keep a certain separation of concerns. The typical syntax to establish an connection is:\n\n\n connect(sender, &Foo::somethingHappened, receiver, &Bar::doStuff);\n\nThis connects the signal _somethingHappened_ in our _sender_ of Type _Foo_ to the member function _doStuff_ in our _receiver_ (context object) of type _Bar_. Whenever _sender_ “emits” _somethingHappened_ , _doStuff_ on _receiver_ will be called. The neat part about Qt connections is that when _receiver_ gets destroyed, the connection is severed automatically. However, you can not just connect a signal to a member function but also use a lambda:\n\n\n connect(job, &WallpaperFinder::wallpaperFound, [this](const QString &path) {\n m_wallpapers << path;\n });\n\nIn our hypothetical wallpaper selector when the “job” that goes looking for wallpapers found one, it emits a signal and tells us the path of the file, so we can show it to the user. Now what happens when the user closes the dialog (which then gets destroyed) before the job has finished? Well… _job_ still emits the signal which then results in our lambda being called. And then we try to access _m_wallpapers_ on _this_ which is long gone. Boom!\n\nThe fix is easy: provide a __ “context object”, too, just like you would with pointer to member function:\n\n\n connect(job, &WallpaperFinder::wallpaperFound, **this** , [this](const QString &path) {\n m_wallpapers << path;\n });\n\nIf _this_ gets destroyed, the connection is severed, our lambda will no longer be called and all is well. The _receiver_ object also decides what thread the slot is called, i.e. it will be called in the thread the receivers “lives in”. Context-less connections are always of _DirectConnection_ type. Since Qt 6.7 you can actually enforce the use of a context object by defining _QT_NO_CONTEXTLESS_CONNECT_.\n\n\n add_definitions(-DQT_NO_CONTEXTLESS_CONNECT)\n\nIt requires you think about the lifetime of your objects more and make a conscious decision about what your context object is. It also removes one thing to look out for in code review. I started adding this option to a couple KDE repositories to improve the quality of our code and I encourage you to do that, too! It probably comes to no surprise that in general, the bigger and older a repository, the higher the probability of it using non-ideal code.\n\n### What context object to use?\n\nOf course, the situation is not always as simple as our example above. Here’s a few tips and tricks:\n\n * Look at the lambda captures. If you capture _this_ , chances are, you want _this_ as your context object.\n * If you capture a single object, perhaps you want it as your context object rather than _this_. If you use the sender, too, that’s fine, capture them both:\n`connect(job, &Job::finished, manager, [job, manager] {\nmanager->report(job);\n}); `\nWhen the sender gets destroyed, evidently the connection is useless and will be severed.\n * You can try to avoid capturing _this_ by doing an init capture, i.e. `[foo = m_foo] { ... }`\n * Perhaps you don’t even need a lambda and can just connect to the method directly. Lambdas are so ubiquitous that you tend to forget you could just replace\n`connect(job, &Job::finished, [timer] {\ntimer->start();\n});`\nwith:\n`connect(job, &Job::finished, timer, &QTimer::start);`\n * At last, you may also use the sender as context object.\n * A context object must be a _QObject_ , though. If you don’t have one, you’ll have to find another way. For instance, _QObject::connect_ returns a _QMetaObject::Connection_ object that you can store in a member variable and then _disconnect_ when appropriate, like in your destructor.\n * For connections where it doesn’t _really_ matter _qApp_ can also be an option.\n\n\n\nI’m a huge fan of _QT_ENABLE_STRICT_MODE_UP_TO_ that lets you turn on most strictness features in a single shot. The biggest hurdle of rolling that out more widespread in KDE repositories is actually the Java-style iterators. Qt hates them, many use them, particularly for mutating a container, and imho they’re much more pleasing to look at than STL algorithms. If you start a new project, however, do consider setting your baseline to be as strict as it can be!",
"title": "Qt No Contextless Connect"
}