Skip to main content

Search...

C++ Quality by Design

C++ is 45 years old and yet deeply rooted in autonomous driving, medical devices and AI libraries. What the Core Guidelines have to do with it.

10 min read
Cover for C++ Quality by Design

The C++ Core Guidelines are a community-supported set of rules for secure, modern C++ development, published by language inventors Bjarne Stroustrup and Herb Sutter. Their core: clear ownership semantics, i.e. whether code owns a resource or only borrows it. According to the transcript, incorrect ownership is the most common cause of crashing programs.

Key Takeaways

  • Ownership semantics is the most common source of errors in C++: a pointer alone does not show whether ownership or only a loan is being transferred, which leads to crashes and resource leaks.
  • C++ has received a new version every three years since the 2011 standard, with the 2011 and 2020 standards having fundamentally changed the programming style.
  • In safety-critical and regulated areas such as medical technology or automotive, refactoring to new language versions is usually not worthwhile because every change triggers the certification process again.
  • The C++ Core Guidelines are supported by the community, not by a standardization committee, and explain by design how to model ownership, interfaces and resources correctly.
  • AI libraries such as those behind Python frameworks have a Python wrapper but are implemented in C++, showing that the language remains at the core of modern high-performance systems.

C++ is 45 years old and still highly active

C++ is one of the oldest high-level languages still in widespread use today, and it is still being actively developed. The language is around 45 years old. Bjarne Stroustrup, the inventor of C++, spoke of 40 years at a conference in Berlin a few years ago, and more years have passed since then.

Anyone who thinks C++ is old hat is wrong. The language is used in control units, components and libraries. It is driven forward by a very active community that adopts modern concepts and transfers them into new standards.

Age brings with it a legacy. C++ was designed for hardware that no longer exists today. Nevertheless, it has remained a general-purpose language, not one that lives in a niche like Fortran or Cobol. It has a general purpose and is developing almost in step with Python and Java, just a little slower because it is standardized.

Why C++ changes every three years

Since C++11, a new standard has been published every three years: 11, 14, 17, 20, 23. Two of these versions are so massive that they change the way programming is done.

C++ is under a strong wave of requirements. The language is used extensively in safety-critical systems, in the embedded sector and in the automotive industry. In addition, there are safety requirements from standards such as MISRA C++. New features, new requirements from the industry and high safety standards are being added to an already complex language.

The complexity is no coincidence. A complex domain creates a complex language. That’s why it pays to have an idea of how to use C++ correctly by design and minimize the likelihood of tripping yourself up.

The three big leaps in C++ evolution

The evolution of C++ can be reduced to three stages. Each marks a clear break in the way of programming.

StandardMeaning
C++98First standard, the language is defined.
C++11The language is greatly revolutionized: Lambdas, move semantics, a first idea of concurrency, new libraries. From this point on, we speak of modern C++, before that of legacy C++.
C++20Four feature series take the language to another level: Ranges, Modules, Coroutines and Concepts.

The 20 standard is so different that there is no established name for it yet. For 11 and 17, “modern” fits, for 20, “postmodern” doesn’t scale. The only thing that is clear is that it is a massive break that is changing the language considerably.

Don’t refactor old code on principle

You should not rewrite existing, working C++ code simply because a new standard is available. C++ follows a meta-rule: a modern compiler must also be able to translate old 98 code.

The sensible strategy is to use new technology when an error is found or something new is created. Completely rebuilding working old code entails two risks. You introduce new bugs, and you throw away the experience contained in this code because your customers have long since found the old bugs.

This is exacerbated in highly regulated environments. In the medical sector, a device has to be approved and every change can trigger the whole process again, right up to clinical evaluation. Changes are often only made when the underlying chip is no longer available. This is why companies in this sector buy chips for years to ensure planning security.

What the C++ Core Guidelines are

The C++ Core Guidelines are a collection of best practices that describe how to write good, modern C++ code by design. They cover interfaces, functions, classes, inheritance and other areas, in around 14 sections with many individual rules.

Unlike standards such as MISRA C++ or Autosar C++14, the Core Guidelines are not supported by a standardization committee or a company, but by the community. The two main editors are Bjarne Stroustrup, the inventor of C++, and Herb Sutter, the chairman of the standardization committee.

The established security standards have a problem with age. MISRA C++ dates back to 2008 and partly trains technology that is no longer used today, even if it is currently being updated. If you don’t want to change the code you wrote two years ago today, you haven’t learned anything in that time. In this view, a generation of software takes two to three years.

The core guidelines are difficult to read in their original form. They resemble the book “Design Patterns” by the Gang of Four from 1994: important in terms of content, but monotonous because every rule is worked through mechanically. Some rules are redundant, some poorly explained, some very important, some less so. They need a readable cover around them.

Ownership versus borrowing: the most important rule

By far the most important design rule concerns the difference between owning and borrowing a resource. If a C++ program crashes, it is almost always because these two concepts have been mixed up.

A resource can be memory, a mutex, a file handle, a socket or a device that is started up and shut down again. As soon as you take responsibility for something, you need to clarify: Do you own it, or are you just borrowing it?

The design flaw in classic C and C++ lies in the pointer. A pointer models both ownership and borrowing, and you can’t tell which is meant. If you hold a naked pointer in your hand, you don’t know whether you have to release the resource again or not.

If I throw my car keys to my son, is he the owner or have I just lent him the car? If he is the owner, he can drive it against the tree. If I only lent it to him, he will have a problem with me.

Rainer Grimm

Modern C++ solves this using clear types of transfer to functions: by value, by reference, by pointer, by unique pointer, by shared pointer. Each of these variants models exactly whether ownership is transferred or something is borrowed. Programming on documentation is not enough. The binding must be in the type.

The less you program, the better your programs will be

A central rule of thumb is to give the compiler as much freedom as possible. The compiler is very clever, and the more you dictate to it, the worse the result will be, both in terms of errors and performance.

An example of this are the six special member functions that the compiler generates itself if required: default constructor, destructor, copy and move constructor and copy and move assignment operator. As soon as you design something incorrectly at one point, the compiler stops generating it because it is paranoid. Then you have to write all six yourself, with the corresponding potential for errors.

Performance also benefits from restraint. Optimizers work best with local code because they have all the information and can draw the most conclusions from it. Local code is a simple, effective rule.

Maintainability comes from other people’s code, not your own

You write maintainable C++ code by not inventing the wheel yourself. A core guideline recommends using the standard library or, if that is not enough, very well-established libraries such as Boost.

The advantage is clear. If you rely on established libraries, you are no longer the maintainer of this code. Someone else has built the abstraction, you are just the user. This ensures maintainability from the outside.

C++ has historically had a weakness when it comes to tooling. With C++20, modules are added. In C++23, import std is sufficient to integrate the entire standard library in one go without having to deal with headers.

Macros must go

A broad consensus in the C++ community can be summed up in one formula: Macros must go. With C++20 and 23, macros can be got rid of completely because there is no longer any reason for them.

The replacements are ready. constexpr functions run at compile time, conditional compilation also works via constexpr, and with modules the need for include files disappears. import std is significantly faster and completely ignores macros.

How C++ deals with errors

C++ has a weakness in error handling because exceptions cause costs, especially at the moment they are thrown. As long as nothing happens, they cost nothing, which is normally exactly right.

C++23 introduces std::expected, a data type from the functional world. It can carry an expected and an unexpected value. You operate both channels and the error is propagated through the call chain. If an error occurs, processing stops and you receive the error message.

Functional ideas characterize modern C++

Modern programming languages are increasingly adopting ideas from functional programming, and C++ does this particularly strongly. The background: programming is too complex for our limited minds, which is why formal concepts from mathematics flow into the languages.

Particularly with concurrency and threading, people try to make systems more formal so that they can prove in case of doubt that they do what they are supposed to do. The most influential language here in recent years is Haskell. Hardly anyone uses Haskell productively, but its ideas have a strong influence on other languages.

In C++20, this can be seen in Ranges, the second implementation of the Standard Template Library, which introduces functional ideas such as function composition and lazy evaluation. Concepts was also significantly influenced by people from the functional world.

Abstraction for zero costs as a unique selling point

C++ pursues a high standard: abstraction without additional costs. The meta-rule is “don’t pay for anything you don’t use”. This is exactly where C++ differs from other languages.

Java and Python offer abstraction, but not at zero cost. C offers no additional costs, but also no abstraction. C++ wants both, and Rust goes in a similar direction.

An upcoming example is Compile Time Reflection, which C++ is very likely to get in C++26. This makes it possible to query at compile time which type is present and what it supports. This is useful for testing and serialization. Unlike runtime reflection in Python or Java, this should be done without runtime costs, which makes implementation much more complicated.

Why C++ is a survival criterion for entire industries

The German automotive industry and its suppliers are heavily dependent on C++. Autonomous driving and the evaluation of video data are implemented in C++.

C++ is also the way forward in the field of AI. There are convenient Python wrappers, but the actual implementation of the libraries is in C++. Someone has to write these libraries, and this is rarely done in Python.

Twenty-year-old software is both a blessing and a curse. A blessing because it has been on the market for so long. A curse because you carry the burden with you permanently. This is precisely the requirement for a language that is old and still wants to remain modern.

Share this page

Related Posts