Making objects or methods const has two benefits. First, the compiler will complain when you break the contract. Second, you tell the user of the interface that the function will not modify the arguments.

The C++ Core Guidelines has five rules to const, immutability, and constexpr. Here are they:

Okay, this rule is quite easy. You can make a value of a built-in data type or an instance of a user-defined data type const. The effect is the same. If you want to change it, you will get what you deserve: a compiler error.

Declaring member functions as const has two benefits. An immutable object can only invoke const methods and const methods cannot modify the underlying object. Once more. Here is a short example which includes the error messages from GCC:

Here is a nice use-case for mutable. Imagine, your class has a read operation which should be const. Because you use the objects of the class concurrently you have to protect the read method with a mutex. So the class gets a mutex and you lock the mutex in the read operation. Now, you have a problem. Your read method cannot be const because of the locking of the mutex. The solution is to declare the mutex as mutable.

Here is a sketch of the use-case. Without mutable, this code would not work

If you want to share a variable immutable between threads and this variable is declared as const, you are done. You can use immutable without synchronisation and you get the most performance out of your machine. The reason is quite simple. To get a data race, you should have a mutable, shared state.

Data Race: At least two threads access a shared variable at the same time. At least one thread tries to modify it.

There is only one problem to solve. You have to initialise the shared variable in a thread-safe way. I have at least four ideas in my mind.

Initialise the shared variable before you start a thread.

Use the function std::call_once in combination with the flag std::once_flag.

Use a static variable with block scope.

Use a constexpr variable.

A lot of people oversee the variant 1 which is quite easy to do right. You can read more about the thread-safe initialisation of a variable in my previous post: Thread-safe Initialization of Data.

Rule Con.5 is about variant 4. When you declare a variable as constexpr constexpr double totallyConst = 5.5;, totallyConst is initialised at compile-time and, therefore, thread-safe.

That was not all to constexpr. The C++ core guidelines forgot to mention one import aspect of constexpr in concurrent environments. constexpr functions are sort of pure. Let's have a look at the constexpr gcd .

A constexpr function can be executed at compile time. There is no state at compile time. When you use this constexpr function at runtime the function is not per se pure. Pure functions are functions that return always the same result when given the same arguments. Pure functions are like infinitely large tables from which you get your value. The guarantee that an expression returns always the same result when given the same arguments is called referential transparency.

Pure functions have a lot of advantages:

The function call can be replaced by the result.

The execution of pure functions can automatically be distributed to other threads.

A function call can be reordered.

They can easily be refactored or be tested in isolation.

In particular, the point 2 makes pure functions so precious in concurrent environments. The table shows the key points of pure functions.

I want to stress one point. constexpr functions are not per se pure. They are pure when executed at compile time.

What's next

That was is. I'm done with constness and immutability in the C++ core guidelines. In the next post, I start to write about the future of C++: templates and generic programming.

Get your e-book at Leanpub:

The C++ Standard Library

Concurrency With Modern C++

Get Both as one Bundle

With C++11,C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages.

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more the 100 source files.

Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 600 pages full of modern C++ and more than 100 source files presenting concurrency in practice.

Get your interactive course at educative

Modern C++ Concurrency in Practice: Get the most out of any machine

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.