C++11 – How to Make the Switch to C++11

cc++11

I've been programming in C++ for a while now, but mostly things centered around the low-level features of C++. By that I mean mostly working with pointers and raw arrays. I think this behavior is known as using C++ as C with classes. Despite this, I only having tried C recently for the first time. I was pleasantly surprised how languages like C# and Java hide these details away in convenient standard library classes like Dictionaries and Lists.

I'm aware that the C++ standard library has many containers like vectors, maps and strings as well and C++11 only adds to this by having std:: array and ranged loops.

How do I best learn to make use of these modern language features and which are suitable for which moments? Is it correct that software engineering in C++ nowadays is mostly free of manual memory management?

Lastly, which compiler should I use to make the most of the new standard? Visual Studio has excellent debugging tools, but even VS2012 seems to have terrible C++11 support.

Best Answer

First, some rules of thumb:

  • Use std::unique_ptr as a no-overhead smart pointer. You shouldn’t need to bother with raw pointers all that often. std::shared_ptr is likewise unnecessary in most cases. A desire for shared ownership often betrays a lack of thought about ownership in the first place.

  • Use std::array for static-length arrays and std::vector for dynamic.

  • Use generic algorithms extensively, in particular:

    • <algorithm>
    • <numeric>
    • <iterator>
    • <functional>
  • Use auto and decltype() wherever they benefit readability. In particular, when you want to declare a thing, but of a type that you don’t care about such as an iterator or complex template type, use auto. When you want to declare a thing in terms of the type of another thing, use decltype().

  • Make things type-safe when you can. When you have assertions that enforce invariants on a particular kind of thing, that logic can be centralised in a type. And this doesn’t necessarily make for any runtime overhead. It should also go without saying that C-style casts ((T)x) should be avoided in favour of the more explicit (and searchable!) C++-style casts (e.g., static_cast).

  • Finally, know how the rule of three:

    • Destructor
    • Copy constructor
    • Assignment operator

    Has become the rule of five with the addition of the move constructor and move assignment operator. And understand rvalue references in general and how to avoid copying.

C++ is a complex language, so it’s difficult to characterise how best to use all of it. But the practices of good C++ development haven’t changed fundamentally with C++11. You should still prefer memory-managed containers over manual memory management—smart pointers make it easy to efficiently do this.

I would say that modern C++ is indeed mostly free of manual memory management—the advantage to C++’s memory model is that it’s deterministic, not that it’s manual. Predictable deallocations make for more predictable performance.

As for a compiler, G++ and Clang are both competitive in terms of C++11 features, and rapidly catching up on their deficiencies. I don’t use Visual Studio, so I can speak neither for nor against it.

Finally, a note about std::for_each: avoid it in general.

transform, accumulate, and eraseremove_if are good old functional map, fold, and filter. But for_each is more general, and therefore less meaningful—it doesn’t express any intent other than looping. Besides that, it’s used in the same situations as range-based for, and is syntactically heavier, even when used point-free. Consider:

for (const auto i : container)
    std::cout << i << '\n';

std::for_each(container.begin(), container.end(), [](int i) {
    std::cout << i << '\n';
});

for (const auto i : container)
    frobnicate(i);

std::for_each(container.begin(), container.end(), frobnicate);
Related Topic