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 erase–remove_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);
g++ -std=c++11