Julien Jorge's Personal Website

Book Review: Embracing Modern C++ Safely

Sat Nov 19, 2022

Table of contents


Note: This post is based on the French one published on LinuxFr.org, written by great contributors and myself.


Presentation

Embracing Modern C++ Safely by John Lakos, Vittorio Romeo, Rostislav Khlebnikov, and Alisdair Meredith, is a book about the features introduced in the C++ language in its versions 11 and 14. The authors are Bloomberg employees and present in this book the additions to the language in view of the experience they acquired by its use in their day-to-day work.

I have read it cover to cover, and I am going to tell you why it is worth the money.

Disclaimer: I got no free copy of this book, I had to pay mine :(

Inside the Book

As Andrei Alexandrescu put it in the preface, this book is a diff from C++98 to C++14. It is not a tutorial nor a collection of good practices, and it actually contains very few recommendations. Instead, it is a complete inventory of the new features introduced in the language, analyzed and explained long and large, especially regarding how “safe” they are to use.

In this book the safety is considered in regard to the capacity of a feature to harm a code base. Something that cannot be misused, like nullptr or the override keyword, is safe, while something very niche, whose application is between usefulness and obfuscation, is categorized as unsafe. The book group the features in three categories: safe, conditionally safe, and unsafe.

For each feature, the book describes the feature in deep details, then provides an extended list of usual use cases, the potential pitfalls, and the main annoyances. Some sections also contain an annex to go even further in the feature. Everything is provided to weight the pros and cons of a feature, backed up by the experience of very competent developers. In a sense, this book teaches the experience rather than the features.

Physically, the book is huge. Around 1,400 pages for 18.5 × 13 × 5 cm. (7.09 × 5.12 × 1.97 in.), it weights more than 2 kg. (4.41 lbs.). Inside the book the pages are well spaced out, readable, and the code snippets are well integrated.

The safe features part contains the following: attributesconsecutive >decltype — functions defined as defaultdelegated constructorsdeleted functions — explicit operators — static variables in functions — unnamed types as template arguments — the long long type — [[noreturn]] attribute — nullptroverrideraw string literalsstatic_asserttrailing return typesunicode literals — type aliases with usingaggregate type initializationbinary literals with 0b[[deprecated]] attribute — ' as a digit separatorvariables template.

In the conditionally safe features one will find: alignasalignofauto variables — braced initialization — constexpr functions and variables — default member initialization in classes and unions — enum classextern templateforwarding references — generalized PODs — inheriting constructorsstd::initializer_listlambdasnoexcept operator — opaque enums — range forstd::move and rvalue referencesunderlying types for enums — user-defined literalsvariadic templates.

Finally, the unsafe features are: the [[carries_dependency]] attribute — final — extended friend declarations — inline namespacenoexcept specifier — ref-qualified member functionsunions with non-trivial types — automatic return type deductiondecltype(auto).

As you may have observed from the above, these lists are only about the C++ language itself. The book does not cover the many changes occurring in the standard library when switching from C++98 to 11 or 14.

An Example of a Safe Feature

C++11 extends the specification for the declaration of block-scope static variables by requiring that concurrent initialization must wait for the completion of any currently ongoing initialization, thus guaranteeing that there would be no data-race in the initialization of the variable itself. Using static to declare a local variable with static storage duration is categorized as a safe feature.

Here is a code snippet the author used to illustrate this feature in the book (comments are mine):

Logger& getLogger()
{
  // Even if two threads call getLogger() simultaneously,
  // local will be constructed only once.
  static Logger local("log.txt");
  return local;
}

In order to illustrate a potential pitfall, the authors introduce the following FileManager class below:

struct FileManager
{
  FileManager()
  {
    getLogger() << "Starting up file manager…";
    // …
  }

  ~FileManager()
  {
    getLogger() << "Shutting down file manager…";
    // …
  }
};

FileManager& getFileManager()
{
  // Global fileManager, initialized on the first call
  // to getFileManager().
  static FileManager fileManager;
  return fileManager;
}

The authors then explain that the order of the initial calls to getFileManager() and getLogger() does not matter. If the former is called before the latter, it will trigger the construction of the logger. Otherwise, if the calls happen the other way around, the logger will have already been constructed when the constructor of FileManager will be executed.

However, the order of destruction is important (note that the order of destruction is required to be the inverse of the creation order).

  • if FileManager is destructed first, everything is fine.
  • otherwise, the program will have undefined behavior because the destructor of FileManager will call getLogger(), which will now return a reference to an object that does not exist anymore.

As you may have observed, the issue described here is directly related with the use of static variables in functions; it has nothing to do with the thread-safe initialization introduced in C++11.

Finally, after the potential pitfalls, the authors list some annoyances. Here they explain, rightfully, that in the case of a function used in a mono-thread context, the initialization of a static local variable will be needlessly guarded by synchronization primitives, and the call will not be able to be inlined.

Personal Feedback

This book is a bit like the one I write with the additional characteristics that it is more detailed, better informed, far more neutral, and written by people who know better than me. It’s a bit frustrating but I am very glad that Embracing Modern C++ Safely exists :)

It is totally worth the money and I absolutely recommend to acquire it, whether to get yourself up to date if you already use C++11 or C++14, or to benefit from the knowledge of very qualified people if you want to improve your C++ skills. Each section is very complete and the pros and cons are well explained, with handy examples.

One may consider the book to be a bit verbose, as it is not unusual to read an information, then again in the form of a code snippet, then again as a textual description of the code. Sometimes there is even another occurrence a few pages later. It was my feeling at first, but when I entered tougher topics, I was very happy to get the information many times, in different forms. For example, the 120 pages of the section about rvalue references contain a full review of value categories (you know: rvalue, xvalue, prvalue, etc.) and is by far the most educational resource I have ever seen on this topic.

Another good side of this verbosity is that every section is self-contained, thus the book can easily be read out of order.

Also, as it is a first edition, the book contains some minor typos here and there. They would undoubtedly be seen by people at ease with the language but may disturb other readers. Maybe the latter should wait for the next edition then.

Finally, I note the intent by the authors to be factual and to avoid any kind of personal opinion. They absolutely succeeded. For example, in the potential pitfalls and other annoyances, the problems are simply listed without any kind of gravity, absolute or relative to the others. Some of these examples sometimes seem a bit far-fetched and I may find myself wondering “but who would do that?” when reading some code snippets. Nevertheless, since the authors want to expose facts, it is appropriate to present these examples with no discrimination.

Where To Get The Book

Many libraries sell the book, one can find a list on the official website. Count something like $50 to buy it.