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 groups 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:
attributes —
consecutive >
— decltype
—
functions defined as
default
— delegated constructors
—
delete
d functions
—
explicit
operators
— static
variables in functions — unnamed types as template arguments — the long long
type —
[[noreturn]]
attribute
— nullptr
—
override
—
raw string literals —
static_assert
— trailing return types — unicode literals —
type aliases with using
— aggregate type initialization
— binary literals
with 0b
— [[deprecated]]
attribute
— '
as a digit separator — variables
template.
In the conditionally safe features one will find:
alignas
—
alignof
—
auto
variables —
braced initialization —
constexpr
functions and variables — default member
initialization
in classes and unions — enum class
— extern template
— forwarding
references
— generalized PODs — inheriting
constructors
—
std::initializer_list
— lambdas —
noexcept
operator —
opaque enums — range
for
—
std::move
and
rvalue
references
— underlying
types for
enums — user-defined
literals —
variadic
templates.
Finally, the unsafe features are: the
[[carries_dependency]]
attribute —
final
— extended
friend
declarations — inline namespace
—
noexcept
specifier — ref-qualified member
functions
— unions with non-trivial
types — automatic
return type
deduction
— decltype(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 callgetLogger()
, 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.