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.
If you're following our Youtube channel you might have heard me talking about QVarLengthArray.
If you're not... you should follow us! But let me give you a quick recap.
QVarLengthArray is a Qt container that acts like a vector; its elements are stored contiguously in memory and it has a dynamic size. At any time we can add or remove elements from it.
Unlike std::vector or QVector, QVarLengthArray has a small buffer pre-allocated inside itself. The idea is pretty simple: if in the "common case" it only needs to store a relatively small number of elements, one can avoid paying for a heap allocation. (To say it in other terms: it's a "vector with small object optimization".)
This is realized by storing elements directly inside the QVarLengthArray's internal buffer, in case they fit.
If the QVarLengthArray grows too much and the number of elements exceeds the internal buffer's size, then a heap allocation is used and QVarLengthArray becomes pretty much like an "ordinary" vector.
Of course, whether this "common case" is realistic depends on the particular context. In Qt this class is used when indeed there's statistical/profiling data indicating that we could spare the heap allocation.
In code, QVarLengthArray's class layout looks something like this (note, this is hugely simplified):
template<typenameT, qsizetype Prealloc =256>classQVarLengthArray{// Points to either the internal storage (if capacity <= Prealloc),// or to a heap-allocated array otherwise. Since it points to the first// element, it's begin(). T *ptr;// Current size and capacity qsizetype size; qsizetype capacity;// The internal bufferalignas(T) std::byte internal_storage[Prealloc *sizeof(T)];};
QVarLengthArray is supposed to be used a drop-in replacement for something like vector. Typically you'll see it used inside a function as a temporary storage for some algorithm:
voiddoWork(){// number of elements is usually "small" QVector<Element> v; v.reserve(...);while(...){// gather the elements to process v.push_back(element);}for(const Element &e : v){// process themprocess(e);}// elements are contiguoussome_c_api(v.data(), v.size());}
Here we could very easily switch to QVarLengthArray:
voiddoWork(){// Estimate: max 16 elements "most of the time" QVarLengthArray<Element,16> v; v.reserve(...);while(...){// gather the elements to process v.push_back(element);}for(const Element &e : v){// process themprocess(e);}// elements are contiguoussome_c_api(v.data(), v.size());}
The Tradeoff
What is happening here is that we are trading a certain heap allocation (with std::vector) for some extra stack usage (the QVarLengthArray object itself is big) and a heap allocation that happens only in the "unlikely" case where we have too many elements to fit in the internal buffer. The key is guessing the preallocated size correctly to make this trade-off worthwhile.
So that's it? Just go and use QVarLengthArray?
Well, not so quick! There is one very important API difference between and vector classes. It's so important that I'll highlight it in red:
QVarLengthArray<T>::resize(N) does not necessarily initialize its elements.
The Quest For Uninitialized Storage
What do I mean by that? Consider this simple example:
QVector<int> vec;vec.resize(10);// all zeros -- guaranteedQVarLengthArray<int> qvla;qvla.resize(10);// indeterminate values!
When you use QVarLengthArray<T>::resize on a trivially constructible type T, or similarly when you use the corresponding resizing constructor (e.g. QVarLengthArray<int> tenInts(10);), the elements in the container are not value-initialized. Instead, they are left in an indeterminate state. Needless to say, attempting to read or manipulate an element of our container will likely trigger undefined behavior.
Bear in mind, this is by design, and documented, and auto-tested:
If the value type is a primitive type (e.g., char, int, float) or a pointer type (e.g., QWidget *), new elements are not initialized. For other types, the elements are initialized with a default-constructed value.
(The wording is a bit inaccurate, but the gist is there.)
The idea here is pretty simple: avoiding paying for the initialization of elements if the following code is going to overwrite them anyway. In other words, use QVarLengthArray as some sort of managed "uninitialized storage".
This is a very sought-after feature from standard containers and allocation facilities: in a lot of "low level" code we need to allocate storage, and we want to manage it properly (in a container, using smart pointers, etc.). Yet, the same facilities also needlessly initialize the storage -- which is a waste if we are going to overwrite the content:
autoreadDataFromSocket(){ std::vector<std::byte> buffer; buffer.resize(socket->availableBytes());// resizes AND initializes socket->read(buffer.data(), buffer.size());// overwrites the contents.return buffer;}
Why did we bother with initializing the vector's contents if we are going to overwrite them anyways? Can't we do better?
Allocating Uninitialized Data in Modern C++
Luckily, C++20 and C++23 bring us a bunch of improvements in the area.
Smart Pointers
In C++20 we have make_unique_for_overwrite and make_shared_for_overwrite. They complement make_unique and make_shared by allowing "uninitialized" allocations. Suppose that you want to dynamically allocate 100k integers and not initialize them. You know the drill and you use make_unique:
This allocates, but also initializes the array. That's a huge waste of time if the data is meant to be overwritten (from a file, database, socket, ...).
The reason why the integers are initialized has to do with the specification of make_unique. In the case above, it is defined to do this:
// std::make_unique<int[]>(100'000) returns this:return std::unique_ptr<int[]>(newint[100'000]())// ^^ look here
But we don't want zero initialization. How do we achieve that in C++? We use default initialization, which leaves the values in an indeterminate state. The integers in the array are initialized, in the sense that they exist as far as the abstract machine is concerned; but no initialization code is emitted for them, which is what we want here.
(That's why I was using the word "initialized" between double quotes -- to distinguish from the Language Lawyer notion of initialization.)
This means, however, that we cannot use make_unique because it will always value-initialize. We need to explicitly spell out the allocation, for instance like this:
std::unique_ptr<int[]>p2(newint[100'000]);// no ()
But ew, that's a raw new in my code. Go away!
Thankfully, C++20 has packaged this feature for us. It's called make_unique_for_overwrite:
// C++20: allocates 100k integers, but does not initialize themstd::unique_ptr<int[]> p3 = std::make_unique_for_overwrite<int[]>(100'000);
Strings
Similarly, C++23 allows us to resize a string without value-initializing its data. Quite some care went into the design to try to avoid accidentally creating strings with indeterminate values inside (since string is such a widely used vocabulary type).
In the final version, you're supposed to pass a function that will initialize the new string data right away, effectively closing any "window of opportunity" for an uninitialized string to accidentally exist and maybe get passed around. Here it is, resize_and_overwrite:
// C++23std::string s =~~~;auto oldSize = s.size();s.resize_and_overwrite(100'000,[oldSize](char*buf, std::size_t count){// For starters, s will *reserve* enough space, without initializing it.//// - buf points to the string's storage (i.e. s.data()) *after* the reserve;// - count is the 1st argument to resize_and_overwrite (100k), so// we can re-use this function with different `count`s.// Populate the range [buf, buf+count]. We can mutate the entirety of// the string's buffer. But let's say we're just interested in populating// the new contents -- from position oldSize up to count.for(size_it i = oldSize; i < count;++i) buf[i]=generateData(i);// Notes:// - If we're growing, the newly created storage is *uninitialized*.// Don't read from it!//// - The old contents are still there, and we can access them freely.// If needed, carry `oldSize` manually, to identify where to start// writing (and leave the old contents alone).//// - It is legal to write into buf[count],// but it will be overwritten with \0 when we're done.// We don't need to populate the *entire* buffer -- we may stop short!// The returned value will be the new size of the string.return actual_new_size;});
Honestly, I find this solution quite awkward. I understand what the goal is, but this approach feels not ergonomic at all, hard to compose, and so on.
In any case, we can spot a common theme here:
In all the adopted solutions, the overwrite wording makes it very clear that we are dealing with uninitialized data, which is supposed to be overwritten.
I'll come back to this later.
std::vector
What about std::vector? Well, there has been a separate proposal to solve the problem there. But at the time of this writing, it has not made any progress. The proposal indeed notices that a lot of 3rd party implementations of vector-like containers offer such a facility.
I am not a big fan of this sort of solution. Allocators are invasive; they change the type of your vector, effectively reducing its usefulness as an interface type or vocabulary type. In C++17, polymorphic allocators have been introduced to mitigate this issue -- and guess what? The above solution doesn't work with pmr::allocator, as construction isn't delegated to a memory resource.
The proposal points out that a lot of 3rd party vector implementations do have a non-initializing resize (for instance: Boost.Vector); it would be great™ if we also had one in the Standard.
Qt
What about Qt containers? In Qt, we do not have a non-initializing resize for QString (or QByteArray), but we have non-initializing construction, by using a tag type:
Note: this particular constructor is still undocumented. It's unknown if it will be published in this form; in Qt we don't like tag types. We strongly prefer "named constructors", that is, factory functions, because they're easier to discover and way less error-prone.
And QVector? QVector is missing such functionality, just like std::vector. A patch for adding the same functionality was proposed but abandoned a long time ago.
Back to Square One
But anyway, wasn't this supposed to be a blog post about QVarLengthArray?
Yes, and specifically to bash on the horrible decision of making it not initialize contents, when using a vocabulary (the "container vocabulary") that is always meant to initialize contents.
Why do I call it horrible? Because it goes against any established practice of any other container class, carving yet another "special case to remember" in the already-super-complicated world of C++:
std::vector<int>c1(size);// initializesstd::deque<int>c2(size);// initializesstd::list<int>c3(size);// initializesQVector<int>c4(size);// initializesQVarLengthArray<int>c5(size);// DOES NOT INITIALIZEcont.resize(newSize);// initializes the new elements... UNLESS IT'S A QVLA
This isn't just an itch -- it's a very strong impedance mismatch.
Remember where we started: you had a QVector, maybe in a hot path, and realized that it only stores a few elements (most of the time). Can you spare some memory allocation?
The solution cannot be to "simply" replace it with QVarLengthArray. You also need to review the code and make sure that it's not relying on initializing resize. A 1-liner fix becomes a code refactoring exercise.
Would you now be comfortable with doing that 1-liner change, if it happens to be in some convoluted algorithmic code that you know that works today? Not so sure anymore, right?
Not to mention, this makes QVarLengthArray bad to use in generic code. Many people complain about the poor usability of things like std::vector<bool>, (also) because they're awkward to use in generic code:
template<typenameContainer,typenameT>voidfill(Container &container,const T &t){for(auto&e : container) e = t;}std::vector<int> v;fill(v,42);// OKstd::vector<bool> v2;fill(v2,true);// ERROR! Cannot create a (language) reference into a vector<bool>
Raise your hand if you like the usability of this.
Similarly, QVarLengthArray becomes dangerous to use if generic code makes assumptions regarding resizing a generic Container.
Suppose that you want to count the frequencies of elements in a given collection (e.g., counting frequencies of individual characters into a std::string); you could concoct this code:
template<typename<template...> Storage,typenameT>// let users choose the containers they wantautocountFrequencies(T &&collection){ Storage<size_t>c(domain_size);// for char, that's 256for(constauto&e : collection) c[e]++;return c;}
... which does not work with QVarLengthArray's uninitialized resize, because its sized constructor does not initialize. You need to remember to fill the contents. Ew!
I've also stressed how important it is that the Standard Library finds common wording for the uninitialized resizing. That wording is for making users aware of the danger of uninitialized data, which must be written into before use.
Clearly, QVarLengthArray predates any such wording, and we don't have a crystal ball. But it would've been infinitely better for it to simply use any other name but resize() for the purpose! Let's call it resizeUninitialized() and move on. No one would complain.
Unfortunately, now it is way too late to fix it, as it's documented behavior. User code is relying on it. While making resize() always initialize would never change a correct program's behavior, it would affect the performances of sensitive code. So, we cannot do that.
The Moral Lesson
Building a common vocabulary of common behaviors is essential for end-users to be able to use a language effectively. C++ is already riddled with traps at every corner. Hiding non-obvious behaviors in what's otherwise a common vocabulary should be avoided at all costs.
On the other hand, adding "hidden" or non-standard features also means that users will start relying on them (this is Hyrum's Law). So one will never be able to remove them again without breaking something.
My suggestion here is:
always follow the pre-existing nomenclature and behaviors, to minimize surprises for end-users;
if you can't or don't want to (for very good reasons, like the performance benefits of uninitialized resizes), then use a different vocabulary! This will make it very obvious that one is dealing with non-common behaviors.
Thank you for reading.
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.
Senior Software Engineer at KDAB. Giuseppe is a long-time contributor to Qt, having used Qt and C++ since 2000, and is an Approver in the Qt Project. His contributions in Qt range from containers and regular expressions to GUI, Widgets, and OpenGL. A free software passionate and UNIX specialist, before joining KDAB, he organized conferences on opensource around Italy. He holds a BSc in Computer Science.
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.