Trusted Software Excellence across Desktop and Embedded
Take a glance at the areas of expertise where KDAB excels ranging from swift troubleshooting, ongoing consulting and training to multi-year, large-scale software development projects.
Find out why customers from innovative industries rely on our extensive expertise, including Medical, Biotech, Science, Renewable Energy, Transportation, Mobility, Aviation, Automation, Electronics, Agriculture and Defense.
High-quality Embedded Engineering across the Stack
To successfully develop an embedded device that meets your expectations regarding quality, budget and time to market, all parts of the project need to fit perfectly together.
Learn more about KDAB's expertise in embedded software development.
Where the capabilities of modern mobile devices or web browsers fall short, KDAB engineers help you expertly architect and build high-functioning desktop and workstation applications.
Extensible, Safety-compliant Software for the Medical Sector
Create intelligent, patient-focused medical software and devices and stay ahead with technology that adapts to your needs.
KDAB offers you expertise in developing a broad spectrum of clinical and home-healthcare devices, including but not limited to, internal imaging systems, robotic surgery devices, ventilators and non-invasive monitoring systems.
Building digital dashboards and cockpits with fluid animations and gesture-controlled touchscreens is a big challenge.
In over two decades of developing intricate UI solutions for cars, trucks, tractors, scooters, ships, airplanes and more, the KDAB team has gained market leading expertise in this realm.
Build on Advanced Expertise when creating Modern UIs
KDAB assists you in the creation of user-friendly interfaces designed specifically for industrial process control, manufacturing, and fabrication.
Our specialties encompass the custom design and development of HMIs, enabling product accessibility from embedded systems, remote desktops, and mobile devices on the move.
Legacy software is a growing but often ignored problem across all industries. KDAB helps you elevate your aging code base to meet the dynamic needs of the future.
Whether you want to migrate from an old to a modern GUI toolkit, update to a more recent version, or modernize your code base, you can rely on over 25 years of modernization experience.
KDAB offers a wide range of services to address your software needs including consulting, development, workshops and training tailored to your requirements.
Our expertise spans cross-platform desktop, embedded and 3D application development, using the proven technologies for the job.
When working with KDAB, the first-ever Qt consultancy, you benefit from a deep understanding of Qt internals, that allows us to provide effective solutions, irrespective of the depth or scale of your Qt project.
Qt Services include developing applications, building runtimes, mixing native and web technologies, solving performance issues, and porting problems.
KDAB helps create commercial, scientific or industrial desktop applications from scratch, or update its code or framework to benefit from modern features.
Discover clean, efficient solutions that precisely meet your requirements.
Boost your team's programming skills with in-depth, constantly updated, hands-on training courses delivered by active software engineers who love to teach and share their knowledge.
Our courses cover Modern C++, Qt/QML, Rust, 3D programming, Debugging, Profiling and more.
The collective expertise of KDAB's engineering team is at your disposal to help you choose the software stack for your project or master domain-specific challenges.
Our particular focus is on software technologies you use for cross-platform applications or for embedded devices.
Since 1999, KDAB has been the largest independent Qt consultancy worldwide and today is a Qt Platinum partner. Our experts can help you with any aspect of software development with Qt and QML.
KDAB specializes in Modern C++ development, with a focus on desktop applications, GUI, embedded software, and operating systems.
Our experts are industry-recognized contributors and trainers, leveraging C++'s power and relevance across these domains to deliver high-quality software solutions.
KDAB can guide you incorporating Rust into your project, from as overlapping element to your existing C++ codebase to a complete replacement of your legacy code.
Unique Expertise for Desktop and Embedded Platforms
Whether you are using Linux, Windows, MacOS, Android, iOS or real-time OS, KDAB helps you create performance optimized applications on your preferred platform.
If you are planning to create projects with Slint, a lightweight alternative to standard GUI frameworks especially on low-end hardware, you can rely on the expertise of KDAB being one of the earliest adopters and official service partner of Slint.
KDAB has deep expertise in embedded systems, which coupled with Flutter proficiency, allows us to provide comprehensive support throughout the software development lifecycle.
Our engineers are constantly contributing to the Flutter ecosystem, for example by developing flutter-pi, one of the most used embedders.
KDAB invests significant time in exploring new software technologies to maintain its position as software authority. Benefit from this research and incorporate it eventually into your own project.
Start here to browse infos on the KDAB website(s) and take advantage of useful developer resources like blogs, publications and videos about Qt, C++, Rust, 3D technologies like OpenGL and Vulkan, the KDAB developer tools and more.
The KDAB Youtube channel has become a go-to source for developers looking for high-quality tutorial and information material around software development with Qt/QML, C++, Rust and other technologies.
Click to navigate the all KDAB videos directly on this website.
In over 25 years KDAB has served hundreds of customers from various industries, many of them having become long-term customers who value our unique expertise and dedication.
Learn more about KDAB as a company, understand why we are considered a trusted partner by many and explore project examples in which we have proven to be the right supplier.
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications.
Read more about the history, the values, the team and the founder of the company.
When working with KDAB you can expect quality software and the desired business outcomes thanks to decades of experience gathered in hundreds of projects of different sizes in various industries.
Have a look at selected examples where KDAB has helped customers to succeed with their projects.
KDAB is committed to developing high-quality and high-performance software, and helping other developers deliver to the same high standards.
We create software with pride to improve your engineering and your business, making your products more resilient and maintainable with better performance.
KDAB has been the first certified Qt consulting and software development company in the world, and continues to deliver quality processes that meet or exceed the highest expectations.
In KDAB we value practical software development experience and skills higher than academic degrees. We strive to ensure equal treatment of all our employees regardless of age, ethnicity, gender, sexual orientation, nationality.
Interested? Read more about working at KDAB and how to apply for a job in software engineering or business administration.
Every now and then, when I submit some code for a code review, people tell me that I forgot qAsConst.
Now I have one more enemy, namely: Clazy! It has also started saying this, and I guess it's about time for me to figure out what is going on. When do I need qAsConst and why do I need to know these things?
The Dreaded Warning
The following code is an example of where Clazy and my coworkers tell me to add qAsConst:
Why do I need qAsConst there? Let me tell you a little bit about what's happening behind the scenes, and that will allow us to understand why qAsConst is needed.
Clazy is complaining there regarding a very peculiar interaction that we have between the C++11 range-based for loop that we have there and a Qt container, in this case QStringList. But this can apply to any Qt container.
What is the (potential) problem with that code that Clazy is warning about? Clazy is warning that the code, written like that, could perform a hidden copy of your container. If you just take your container and run through the container, there's no copy in here. It looks like there is no copy, but there could be a copy. Why would you need a copy here?
It all boils down to the fact that Qt containers are implicitly shared or, as we say, Copy On Write (or COW 🐮). In a nutshell, that means that inside each and every Qt container there is a little number -- a reference counter. Every time you try to modify a container, the first thing that Qt does is checks that number.
If the number is bigger than 1, then Qt does a deep copy of that container. We refer to this operation as a detach of the container. That code, written like that, could detach. That's the kind of warning that Clazy is giving you. Since it looks like that, you're not modifying the container in any way. You're just iterating over the StringList, just printing the strings.
Clazy is getting a bit suspicious, thinking, "Okay, so you're taking a copy of the container but you don't want to modify the container? Why are you taking the copy in the first place?"
Where on this particular line does it even have a chance to detach? It's not visible, but it's behind the scenes.
It has to do with the new for loop. How is it implemented? Or even better, what is it equivalent to? Do you know what the new for loop expands to when the compiler sees that and compiles it?
For loops on containers have always been about iterators. You get an iterator pointing to the first element, an iterator beyond the last element, and then you iterate through. You'd assume some iterators and then whatever you're pointing to is copied into your reference, or you'd get a QString reference to that element that it's pointed to.
How does the range-based for loop iterate on an arbitrary container? You've guessed it right, it still uses iterators, even if they're not visible to us. Given a container, the new for loop calls begin() and end() on it, in order to get the iterators that are necessary to actually transverse the container.
Here's the catch: if the container is a Qt container, and it is non-const, then those operations are operations that do the little game I was playing; that is, they go inside the Qt container, check if the reference counter is bigger than 1, and, if it is, detach.
So the very act of calling begin() and end() could detach. As I said, it's not visible but it's there, hidden inside the range-based for loop.
How to Solve the Problem
Make the Container const
When using a Qt container, a necessary condition for a detach to happen is that we are calling methods such as begin() and end() on a container which is not const. Therefore, the simplest approach to fix the whole problem is to make that container const somehow. We could, for instance, take a copy -- a const copy, of course, or even better, a const reference to the container.
Here we're taking a const copy of the container. Now, taking a copy is cheap, given this is a Qt container. The copy on write mechanism implies that the act of taking a copy simply increments the reference counter. (If you take a const reference, you're not even paying for that.)
But now the key aspect is that the for loop is acting on a const container: the begin() that it's going to call is going to be the begin() overload for const containers, which does not detach. Since you have a const container, there's no chance for you to modify the container because it's const. So there is no need to detach at all. And, indeed, this will suppress the warning from Clazy because you cannot detach anymore.
There are better ways, of course. There are a couple of other things that you can do.
Mark the Entire Method As const
The first thing you can do better is realize that the entire print function actually doesn't need to modify this object. So you could mark the entire method as const and that would, as a by-product, make the member m_list const. So, you're good to go.
That would be the best solution. But, of course, it's not general -- maybe you also need to do something else and modify this, so you cannot mark a given method as const.
qAsConst or std::as_const
The second best solution is using something like qAsConst or, equivalently, std::as_const on top of your m_list object.
qAsConst and std::as_const do exactly the same thing. std::as_const is C++17, so if you're not on 17 just yet, you can use the Qt version. What they do is simply give you back a const reference to that container.
What do these functions do? They're just like a const_cast -- they're taking a reference to m_list and adding a const on top of it. So it's just a manipulation of the type, something that's done just for the purpose of the compiler. Now the compiler knows that the thing it gets out of qAsConst is, of course, a reference to a const QStringList; so it can call only the const begin() and the const end(). As we have discussed, those calls will not detach your container.
This solution doesn't cost you anything at runtime. It does not generate any additional code or anything of that sort. It is purely a type manipulation done for the compiler.
Corner Cases
There are some corner cases worth discussing.
Suppose that you have a method that generates a container and you call that method from a range-based for loop because you want to iterate over its results:
Of course Clazy is going to give you a warning there, because you could be detaching the container returned by the function call. So you try to wrap the call in qAsConst:
This code doesn't compile. The reason is a bit complicated, because it has to do with the C++ rules around what exactly you can feed into qAsConst. To keep it simple, you're not allowed to place things like function calls inside qAsConst or, equivalently, inside std::as_const. It's actually a good thing that you can't do that because, otherwise, your program would crash at runtime.
Declare a Local QStringList
Fortunately, for this specific use case, there is a better solution. You can simply declare a local QStringList. Make it const, of course, because that's the purpose of the whole exercise. Then, pass the local QStringList into your for loop. For instance:
QStringList generateStrings();voidprint(){const QStringList list =generateStrings();for(const QString &str : list)// OKprint(str);}
In C++20, I would actually not even need an extra line to declare list. A nice thing about C++20, as a kind of smaller convenience, it added the possibility of adding an initialization inside the range-based for loop. This brings it slightly closer to the old for loop, when you always had the first statement, then the guard, and then the increment.
So you could write something like this, to spare you having this variable around for longer than the loop itself:
QStringList generateStrings();voidprint(){for(const QStringList list =generateStrings();const QString &str : list)// OKprint(str);}
Why does this problem exist to begin with? What if generateStrings() generates and returns a list and there can't be anyone else who has that string list?
QStringList generateStrings(){ QStringList result; result <<"hello"<<"world";return result;}voidprint(){for(const QString &str :generateStrings())// Why a warning? The returned list isn't shared with anyone!print(str);}
You, as a human being, can reason on the code flow and see that the QStringList returned by generateStrings() is not shared. Its reference counter is going to be 1, and that cannot detach. But that's why this is a warning: Clazy is just telling you that this could detach. You have to remember that, in the general case, your generateStrings() function could not be returning a brand new QStringList.
Maybe it's returning a QStringList that you have elsewhere. If that's the case, that return from generateStrings() would implicitly increase the reference counter of your QStringList, because you're creating a new copy. You would actually detach.
Inside your for loop, you would have a QStringList with a reference counter bigger than 1. Clazy, of course, does not have a crystal ball; it cannot predict what your code is going to do. So it's just warning you by telling you this code might detach -- that there is the possibility. It is actually a fairly concrete possibility, given the fact that, typically, when dealing with Qt containers, we always return them by value.
Even if doesn't actually detach right now, one day we might refactor the code. We may say something like, "my string list has to survive the generateStrings() method. Maybe I want to cache it. Maybe I want to save that work". That day, the reference counter is going to increase and the warning would actually be a good warning.
Return a const QStringList?
Instead of just returning a QStringList, generateStrings() could return a const QStringList:
Clazy will not complain here, again because we cannot detach a const container.
However: this is a bad idea. You shouldn't be returning const things from functions, and especially const containers. Why is that? Because you're going to break move semantics.
C++11 introduced move semantics, which allow you to optimize, in general, the return from functions. When you call a function and get a value back, you're going to get a temporary built as result of the function call. You can then move from that temporary into, let's say, a local object. Moving containers is usually very cheap! That's definitely something we want to keep.
If you return const objects however that move gets broken; you can't move from a const object. What happens then? You're going to perform a copy instead. Now, in the case of Qt containers, you can get away with that because copying a Qt container is not particularly expensive. All that you really do is increase the reference counter.
So, as a practical workaround, that could work. But consider this: the moment you decide you don't like QStringList any more and decide to make it a std::vector or something more complicated (some non-Qt container of any sort), you're going to pay for that const because copying a standard container and not moving it is going to cost you a lot. So it's very important to be careful about what you do.
Return a std::vector
You wouldn't have this problem at all with std::vector. The reason for that is that std::vector, and actually all Standard Library containers, are not reference counted; they do not implement this mechanism. Among these other things, this means that a call to begin() into a std::vector object will never copy it behind the scenes. You'll be absolutely fine, if your generateStrings() function returns a std::vector.
To summarize, you need qAsConst() when you iterate in a range-based for loop. That's the first thing. And you need qAsConst when what you're iterating over is non-const.
It could be const if you're in a const method (and the variable is a data member of this) or if it's a variable that you declared as const elsewhere. Otherwise, you need qAsConst but you can only use qAsConst if it's an l-value, something that has a local name, and not the return of a function.
If you are iterating over an object that you get from a function call, save it in a local variable instead (and make it const).
Mutating Iteration
The Clazy warning stems from the fact that your for loop doesn't want to modify your container. In all of our examples, we were using just a debug, or it seemed like we were just reading from the container. Clearly, if you do want to modify the container, then you don't want to apply const at any level! You would need to be working on a non-const container.
But the key aspect of mutating iteration is that, in this case, your iteration variable would have a different type. As you can see, right now we're taking a const QString reference. That means that we cannot mutate the container contents through that variable. If you need to modify the container itself, you'd be taking a non-const QString reference! In that case, you would not get the warning from Clazy, because it would detect that you want to modify the container. If that means a detach, that's the price to pay -- you have a container that's just a shallow copy to some shared data and, if you want to modify it, you need to create your own copy of that data.
In C++23 there is yet another solution that will work in even more cases. We'll cover that at a later time, either on our YouTube channel or as a blog, or both. We'll keep you posted, so please stay tuned.
About KDAB
Trusted software excellence across embedded and desktop platforms
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
Thanks for the interesting article... took me a while to follow though as I think MyClass:m_list needs to be a QStringList (rather than QString), otherwise the loop doesn't read properly. Also the HTML "&" is not getting translated as expected, further reducing the readability.
15 - Nov - 2022
Giuseppe D'Angelo
Hi, You're absolutely right. Something went wrong when reformatting the code, and that also caused a further C&P mistake. Should be fixed now.
30 - Nov - 2022
Martin Koller
What about using Qt's foreach instead ?
Is it deprectaed ?
30 - Nov - 2022
Giuseppe D'Angelo
Hi,
Qt's foreach has different semantics than a range-based foor loop. For instance, you cannot mutate the container's elements when using Qt's foreach. It's also got even more downsides -- they're discussed here https://www.kdab.com/goodbye-q_foreach/
Right now, foreach is not officially deprecated yet, but it's definitely not recommended practice.
Yes, that solution works. I am very conflicted about promoting it.
First, note that you're taking a forwarding/universal reference, and unconditionally moving from it (indeed you named the function moveToConst). This means that one shouldn't use it on lvalues that one wants to keep -- one should stick to std::as_const for those.
This is now adding mental burden: you have to remember to use different tools in different circumstances, when the end goal is exactly the same, just to cope with the idiosincrasies of C++ value categories.
One could develop a more elaborated strategy:
template <typename T>
// lvalues
const T &make_const(const T &t) { return t; }
// rvalues -- need to make it not work with the universal reference
template <typename T, std::enable_if_t<!std::is_reference_v<T>, bool> = true>
const T make_const(T &&t) { return std::move(t); }
for (const QString &s : make_const(stringList) ) { print(s); } // stringList is not moved-from
for (const QString &s : make_const(getStringList()) ) { print(s); } // return of getStringList() moved into make_const's return object
This is now slightly more general. But I'm still not 100% convinced. For instance, suppose you want to give your const container to an adaptor. You create the adaptor and pass to it the result of make_const(container). Since now the adaptor is acting on a const container, the adaptor may need to copy from it, rather than moving from it (effectively, again, one is preventing moves). That's maybe all fine because Qt containers are cheap to copy (except QVLA! except QFlatMap! except...), but again, what happens if you refactor some code and switch from QVector to std::vector? You now have an expensive copy there, maybe without even noticing that a copy is taking place.
I'm afraid that The One Solution To Rule Them All™ will come with C++23:
Jesper K. Pedersen – COO/HR director at KDAB. Jesper has actively developed with Qt since 1998 and, despite his fancy title, still does so.
He has held almost 100 training classes in Qt since 2000. Today, his greatest claim to fame is the QML youtube series and more recently his youtube series called Qt Widgets and More.
Our hands-on Modern C++ training courses are designed to quickly familiarize newcomers with the language. They also update professional C++ developers on the latest changes in the language and standard library introduced in recent C++ editions.
6 Comments
14 - Nov - 2022
Steve
Thanks for the interesting article... took me a while to follow though as I think MyClass:m_list needs to be a QStringList (rather than QString), otherwise the loop doesn't read properly. Also the HTML "&" is not getting translated as expected, further reducing the readability.
15 - Nov - 2022
Giuseppe D'Angelo
Hi, You're absolutely right. Something went wrong when reformatting the code, and that also caused a further C&P mistake. Should be fixed now.
30 - Nov - 2022
Martin Koller
What about using Qt's foreach instead ? Is it deprectaed ?
30 - Nov - 2022
Giuseppe D'Angelo
Hi,
Qt's foreach has different semantics than a range-based foor loop. For instance, you cannot mutate the container's elements when using Qt's foreach. It's also got even more downsides -- they're discussed here https://www.kdab.com/goodbye-q_foreach/
Right now, foreach is not officially deprecated yet, but it's definitely not recommended practice.
4 - Dec - 2022
Vlad
How about this? Wouldn't it help?
5 - Dec - 2022
Giuseppe D'Angelo
Hi,
Yes, that solution works. I am very conflicted about promoting it.
First, note that you're taking a forwarding/universal reference, and unconditionally moving from it (indeed you named the function moveToConst). This means that one shouldn't use it on lvalues that one wants to keep -- one should stick to std::as_const for those.
This is now adding mental burden: you have to remember to use different tools in different circumstances, when the end goal is exactly the same, just to cope with the idiosincrasies of C++ value categories.
One could develop a more elaborated strategy:
This is now slightly more general. But I'm still not 100% convinced. For instance, suppose you want to give your const container to an adaptor. You create the adaptor and pass to it the result of make_const(container). Since now the adaptor is acting on a const container, the adaptor may need to copy from it, rather than moving from it (effectively, again, one is preventing moves). That's maybe all fine because Qt containers are cheap to copy (except QVLA! except QFlatMap! except...), but again, what happens if you refactor some code and switch from QVector to std::vector? You now have an expensive copy there, maybe without even noticing that a copy is taking place.
I'm afraid that The One Solution To Rule Them All™ will come with C++23: