Your cart is currently empty!
Revisiting the state of C++
In late 2022, Kris van Rens wrote about the state of C++ at that time and its challengers. A follow-up after two more years.
In 2022, out of discontent with the evolution process of C++, Google pulled out a substantial amount of its resources from working on C++ and the Clang compiler front-end. As an alternative, it announced the long-term project Carbon, a successor language that can closely interoperate with C++. This and subsequent events posed a watershed moment for C++ because it faced serious criticism for the amount of technical debt it accrued and its relatively slow development pace. From that moment on, it seemed, everybody had a (strong) opinion and loudly advertised it – the amount of critique could no longer be ignored by the C++ committee.
Another aspect of C++ that has been under attack is its lack of memory safety. Memory safety in a programming language refers to the ability to prevent or catch errors related to improper memory access, such as buffer overflows, use-after-free bugs or dangling pointers, through built-in features and guarantees in the language itself. This can be extended to general language safety where all undefined behavior and unspecified semantics are eliminated from the language. Language safety is a concept defined on a spectrum rather than a binary property; some languages are more safe than others. Examples of languages considered safe and still relatively low-level are Swift, Ada and Rust.
Following the intense proverbial heat of the summer of 2022, a series of blows in various forms of public advisories on memory safety explicitly put C as well as C++ in bad daylight. In late 2022, the NSA first came in with a white paper urging us to move away from C and C++. Then, CISA (the US Cybersecurity Infrastructure Security Agency) started advocating for a memory safety roadmap. In 2023 and 2024, even the White House and US Consumer Report proclaimed we should take memory safety more seriously than ever and move to memory-safe languages. There were many more events, but suffice to say that all of them didn’t go unnoticed by the C++ committee.
Admittedly, some of the efforts by C++ committee members to rebut the public attacks came across as slightly contemptuous, often almost downplaying memory safety as “only one of the many potential software issues.” This, to me, sounds an awful lot like a logical fallacy. Sure, many things can go wrong, and a safe language isn’t a panacea. However, software development requirements have drastically changed over the last forty years and today, memory safety is a solved problem for many other languages usable in the same application domain. Officially, ISO workgroup 21 (WG21) instated study group 23 (SG23) for “Safety and Security,” tasked to find the best ways to make C++ a safer language while keeping up the other constraints like backward compatibility – not so easy.
Undeniable gap
I’ve worked with various programming languages in production simultaneously over the past decades. What really stands out to me from all my experiences with C and C++ is the sheer cognitive load they put onto developers.
C is quite a simple language; it’s easy to learn and get started with. However, it’s very hard to become advanced and proficient at it at scale. As a simple language, it forces you to manually address many important error-prone engineering tasks like memory management and proper error handling – staple aspects of reliable, bug-free software. There’s plenty of low-level control, yes, but the ceremony and cognitive burden to get things right is just staggering.
The same largely holds for C++. It does make things better by actually supporting you to write correct code, for example with the standard library featuring smart pointers for memory management. However, the truckloads of language complexity make it hard to use correctly at scale as well.
What’s more, all of these aspects of coding in C and C++ come at no guarantee that things are reliable after compilation. This forces developers to study best practices, use compiler sanitizers and static analyzers and resort to extensive testing, just to be more sure that all is fine. Of course, most of these activities should be part of any healthy software developer mindset, but it’s painful to realize that C and C++ offload the requirement of doing this work to the developer, rather than addressing it in the language directly. Developing a language, as any engineering challenge, is an endless succession of tradeoffs, sure, but there’s an undeniable gap between the capabilities of the ‘legacy languages’ and the needs in the software development space right now. Other, newer languages show that it’s possible to meet these requirements while keeping up the performance potential.
Years away
Most programming languages are constantly being improved over time. If you’re in the C world, however, probably little to nothing is going to change. For many projects today, therefore, it isn’t the right language choice if you want any language safety at all. There are alternatives available, more fit for purpose – if this is possible given your project constraints and preferences.
For C++, it’s a different story. WG21 is now building up to release C++26, which is going to bring huge features to the table, including (most likely) contracts, executors and even static reflection. Game-changers for sure, but mostly addressing language application potential or, in the case of contracts, improving safety and correctness, but still at the cost of manual labor on the part of the developer using it.
New features improve the language but also inherently increase the already quite substantial complexity, while all the old footguns and dangers like undefined behavior are still there. Educating C++ to novices as a trainer remains, in part, an exercise in steering them away from the pitfalls – not really a natural, convenient way to teach or learn.
The ‘parallel universe’ of the Circle C++ language demonstrates how the ostensibly clogged syntax and language definition of C++ is still able to pack many other great features like true enumerators, pattern matching, static reflection and even a borrow checker. Unfortunately, this remarkable one-man show run by Sean Baxter isn’t standardized C++ (and vice versa). Chances are slim that any of these excellent features will land in official C++ anytime soon.
Baxter also has a “Safe C++” proposal, presented to the Safety and Security study group in November of last year. In it, he suggests extending C++ with a “rigorously safe subset” of the language that offers the same safety guarantees as the Rust borrow checker does. I do applaud the effort, but time will tell if at all, and in what form, this proposal will make its way through the often seemingly sluggish C++ language development process. C++26 design work has mostly converged and C++29 is still a couple of years away. Add to that the implementation/industrialization time of these spec versions before they really land on our virtual workbenches, and it might well be a decade from now – if we’re lucky.
Greener pastures
Not all is lost, though. The C++ committee is doing great work progressing the language, and the current state of the language and ecosystem is better than ever. It’s just that the gap between what C++ can offer today compared to what’s shown to be possible in systems programming safety and integrated tooling is huge.
Looking forward a couple of years, I don’t see this gap being filled. Meanwhile, languages like Rust and Swift aren’t standing still. There’s a lot of momentum and prior commitment to C++ in the world, making the industry stick to it, but how long can it sustain the technology gap before industries or application domains move to greener pastures?
In the 4-day training course “C++ fundamentals,” organized by High Tech Institute, Kris van Rens introduces participants to the language basics and essential best practices.