Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News Herb Sutter on Modern C++ Essentials

Herb Sutter on Modern C++ Essentials

This item in japanese

At CppCon 2014, Herb Sutter gave a talk presenting the essential idioms of modern C++ programming. Here is a short summary.

C++ is a complex language, admits Herb, though it must not be complex for every programmer. Herb suggests a view of C++ whereby only a tiny subset of all programmers should concern themselves with the most arcane aspects of the languages, e.g. when dealing with low-level or library code, while all others can just use it in some "default" way that just works.

First case in point is preferring the use of range-for loops. Indeed, while you can write:

for (auto i = begin(c); i != end(c); ++i) { ... }

in modern C++, an easier way of doing the same is:

for (auto& e : c) { ... }

which also provides greater readability.

Pointers, references, new, and delete

Another strong suggestion of Herb's is not using owning *, new, or delete, except when encapsulated inside the implementation of low-level data structures. What is to be preferred to that is unique_ptr, or when you know you are going to share the object, shared_ptr. So you can easily write:

auto p = make_unique<widget>();
auto q = make_shared<widget>();

By using make_unique and make_shared you do not even need bothering about delete.

However, non-owning * and & are still a great resource and their best use case is for passing parameters into functions. What Herb considers a real anti-pattern is using any kind of reference counted variable to pass parameters. This will only be the possible cause for performance problems and should be used only when you want to transfer the ownership of the wrapped object.

Prefer auto to declare local variables

The auto keyword is one of the biggest features of modern c++, according to Herb. auto can be used to deduce a type, but is can also be used to specify a type and stick to it. In you consider the following statement:

auto i = v.begin();

this will correctly deduce the type to be used. This is much easier than the following and goes without much thinking:

vector::const_iterator i = v.begin();

which specifically requires thinking about using a const_iterator.

Correctness is the biggest advantage of auto, but it is also beneficial on other accounts:

  • Maintainability: it makes the code adapt to changes in, e.g., the return value of a function.

  • Performance: as a corollary of correct type deduction, auto also guarantees that no temporary objects are inadvertently created, e.g. when initializing an object.

  • Usability: in special contexts, such as lambda, auto is an enabling factor.

  • Typing convenience: it allows to save a few keystrokes.

There are though a few cases where you cannot use auto, namely when you are dealing with C-arrays or with types that are not moveable or not cheaply moveable, e.g.:

auto lock = lock_guard<mutext> { m };  // error: not movable
auto ai = atomic<int>{}; // error: not movable
auto a = array<int,50>{}; // correct, but expensive

Parameter passing

A large part of the talk is devoted by Herb to discussing parameter passing. His main point here, is that C++98 defaults are still valid in modern C++ and represent a great starting point, with some additional possibilities offered by rvalue optimization. By way of an example, what you should do always is:

class employee {
   std::string name_;
    void set_name(const std::string& name) { name_ = name; }    // standard C++98 convention
    void set_name(std::string&& name) noexcept { name_ = std::move(name); }    // rvalue optimization

On the other hand, Herb suggests to use passing by value mostly in constructors. In other contexts, passing by value, while allowing rvalue optimization, can exact a big performance toll when you pass in a named parameter (i.e., not a temporary object), which would be copied over.


Herb's final suggestion regards the use of tuples to return multiple values:

tie(iter, success) = myset.insert("Hello");
if (success) do_something_with(iter);

Besides stressing the importance of defaults and idioms, Herb also suggests to avoid overthinking, which generally leads to solutions that are overly obfuscated. On all accounts, his recipe is sticking with what the language offers at the most basic level and then measure to look for areas where it might make sense getting your hands dirty to try and get better performances.

Rate this Article