Qt and Trivial Relocation (Part 5) Trivial Relocation and Standard C++
In the previous posts of this series (if you’ve missed them: parts 1, 2, 3, and 4), we have learned about relocation and trivial relocation.
We have explored what relocation means, what trivial relocation means, and how it can be used to optimize the implementation of certain data structures, such as the reallocation of a vector-like container (std::vector, QVector and so on).
Furthermore, we have explored how trivial relocation is connected to move assignments and how some types may be trivially relocatable for move construction but not for assignments. This property can be used to further optimize other operations, such as swaps, erasure, and swap-based algorithms such as std::sort or std::rotate.
In this blog post, we’ll have a look at trivial relocation from a “Standard C++” point of view.
Is trivial relocation allowed in Standard C++?
That’s probably a question we should have asked as soon as we started this journey. Of course, the answer is no, it is not allowed!
Remember how trivial relocation works: we use memcpy a source object(‘s representation) into some storage, and claim that operation realizes the equivalent of move-constructing the source into that storage, plus destroying the source.
The problem is that one can’t just put data into some storage and pretend that an object exists in there. This is only allowed for a specific set of types, such as trivially copyable types. (Note that if a type is trivially copyable, then Qt automatically considers it trivially relocatable.)
However, as we have discussed, many interesting types (QString, std::vector, std::unique_ptr, …) are not trivially copyable, but they would still benefit from trivial relocatability.
Qt simply ignores the Standard wording and just uses trivial relocatability because it makes our code faster, reduces template bloat, reduces compilation times, and so on. I call this “Undefined Behavior That Works In Practice”: yes, the operation is illegal, but so are many others. Qt is in good company here; many other popular libraries employ the same “illegal” optimization — to name a few: Folly, EASTL, BSL, and possibly others; a survey is available here.
Towards standardization
A few years ago, P1144 (“std::is_trivially_relocatable”) emerged. This proposal (which, by the way, has reached its eleventh revision at the time of this writing) was inspired by the work in many existing libraries (including Qt) and introduced the necessary language and library facilities in order to give well-defined semantics to relocation and trivial relocation. Despite its many iterations, it never made it over the “finish line”, voted into C++.
Some time after P1144’s initial revision, P2786 (“Trivial Relocatability For C++26”) was proposed. This was an alternative design, w.r.t. P1144, with different relocation semantics and a different set of enablers.
P1144 and P2786 “competed” for a little while; then, during the ISO C++ meeting in Tokyo (March 2024), the Evolution Working Group voted to adopt P2786 for C++26.
That’s great news, right?
Well, not really. After some analysis, it turned out that P2786’s design is limiting and not user-friendly, to the point that there have been serious concerns that existing libraries may not make use of it at all. In particular, P2786’s relocation semantics do not match Qt’s. With my Qt hat on, it soon became clear that we could not have used P2786 in Qt to replace our own implementation of trivial relocation. This fact raised some serious concerns.
For this reason, I co-authored a “petition paper” (P3236), together with many other library authors, asking EWG to reconsider its decision of going ahead with P2786.
I also have analyzed in detail the problems that I have with P2786’s design in a separate paper (P3233). I don’t want to go through the complete list of issues in a blog post — please read the paper and send feedback. 🙂
In June 2024, during the ISO C++ meeting in St. Louis, I presented P3233 to EWG. If you’re interested and/or want a summary of the issues I raised, check out the slides that I used during my presentation.
P3278R0 (“Analysis of interaction between relocation, assignment, and swap”) was also presented, making many of the remarks that I’ve also made in my paper; I consider a good sign that different authors independently reached the same conclusions.
Eventually, EWG voted to take P2786 back, given the issues raised. I consider it a victory in the face of the danger of standardizing something that does not match the current practices. Still, I understand the frustration at pouring a tremendous amount of work into getting a feature into C++, only to get asked to go back to the drawing board.
So what now?
I hope I can find the time in the next few months to work more on trivial relocation, and present more papers at the next ISO C++ meeting in Wrocław. I think the goal to have trivial relocatability in C++26 is doable; we “just” have to iron out the details.
Regarding the two competing proposals (P1144 versus P2786), in P3236 I actually make an argument that they should be “merged”: each one has some design characteristics that are missing in the other.
Therefore, the trivial relocation story is anything but over. Stay tuned for more updates, hopefully in not the too distant future. 🙂
In the meanwhile, thank you for reading so far.
Overview about all installments:
If you like this article and want to read similar material, consider subscribing via our RSS feed.
Subscribe to KDAB TV for similar informative short video content.
KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.