A summary of Scott Meyers' classic "Effective Modern C++"
The book is awesome and should be read by every C++ developer. I'd like to put a summary here so that every developer can revise it before they go to bed.
If you have a whole week vocation, buy the book and read it thoroughly!
-
During template type deduction, arguments that are references are treated as non-references, i.e., their reference-ness is ignored.
-
When deducing types for universal reference parameters, lvalue arguments get special treatment.
-
When deducing types for by-value parameters, const and/or volatile arguments are treated as non-const and non-volatile.
-
During template type deduction, arguments that are array or function names decay to pointers, unless they’re used to initialize references.
-
auto type deduction is usually the same as template type deduction, but auto type deduction assumes that a braced initializer represents a std::initializer_list, and template type deduction doesn’t.
-
auto in a function return type or a lambda parameter implies template type deduction, not auto type deduction
-
decltype almost always yields the type of a variable or expression without any modifications.
-
For lvalue expressions of type T other than names, decltype always reports a type of T&.
-
C++14 supports decltype(auto), which, like auto, deduces a type from its initializer, but it performs the type deduction using the decltype rules.
-
Deduced types can often be seen using IDE editors, compiler error messages, and the Boost TypeIndex library.
-
The results of some tools may be neither helpful nor accurate, so an understanding of C++’s type deduction rules remains essential.
-
auto variables must be initialized, are generally immune to type mismatches that can lead to portability or efficiency problems, can ease the process of refactoring, and typically require less typing than variables with explicitly specified types.
-
auto-typed variables are subject to the pitfalls described in ### Items 2 and 6.
-
“Invisible” proxy types can cause auto to deduce the “wrong” type for an initializing expression.
-
The explicitly typed initializer idiom forces auto to deduce the type you want it to have.
-
Braced initialization is the most widely usable initialization syntax, it prevents narrowing conversions, and it’s immune to C++’s most vexing parse.
-
During constructor overload resolution, braced initializers are matched to std::initializer_list parameters if at all possible, even if other constructors offer seemingly better matches.
-
An example of where the choice between parentheses and braces can make a significant difference is creating a std::vector<numeric type> with two arguments.
-
Choosing between parentheses and braces for object creation inside templates can be challenging.
-
Prefer nullptr to 0 and NULL.
-
Avoid overloading on integral and pointer types.
-
typedefs don’t support templatization, but alias declarations do.
-
Alias templates avoid the “::type” suffix and, in templates, the “typename” prefix often required to refer to typedefs.
-
C++14 offers alias templates for all the C++11 type traits transformations
-
C++98-style enums are now known as unscoped enums.
-
Enumerators of scoped enums are visible only within the enum. They convert to other types only with a cast.
-
Both scoped and unscoped enums support specification of the underlying type. The default underlying type for scoped enums is int. Unscoped enums have no default underlying type.
-
Scoped enums may always be forward-declared. Unscoped enums may be forward-declared only if their declaration specifies an underlying type.
-
Prefer deleted functions to private undefined ones.
-
Any function may be deleted, including non-member functions and template instantiations.
-
Declare overriding functions override.
-
Member function reference qualifiers make it possible to treat lvalue and rvalue objects (*this) differently.
-
Prefer const_iterators to iterators.
-
In maximally generic code, prefer non-member versions of begin, end, rbegin, etc., over their member function counterparts.
-
noexcept is part of a function’s interface, and that means that callers may depend on it.
-
noexcept functions are more optimizable than non-noexcept functions.
-
noexcept is particularly valuable for the move operations, swap, memory deallocation functions, and destructors.
-
Most functions are exception-neutral rather than noexcept.
-
constexpr objects are const and are initialized with values known during compilation.
-
constexpr functions can produce compile-time results when called with arguments whose values are known during compilation.
-
constexpr objects and functions may be used in a wider range of contexts than non-constexpr objects and functions.
-
constexpr is part of an object’s or function’s interface.
-
Make const member functions thread safe unless you’re certain they’ll never be used in a concurrent context.
-
Use of std::atomic variables may offer better performance than a mutex, but they’re suited for manipulation of only a single variable or memory location.
-
The special member functions are those compilers may generate on their own: default constructor, destructor, copy operations, and move operations.
-
Move operations are generated only for classes lacking explicitly declared move operations, copy operations, and a destructor.
-
The copy constructor is generated only for classes lacking an explicitly declared copy constructor, and it’s deleted if a move operation is declared. The copy assignment operator is generated only for classes lacking an explicitly declared copy assignment operator, and it’s deleted if a move operation is declared. Generation of the copy operations in classes with an explicitly declared destructor is deprecated.
-
Member function templates never suppress generation of special member functions.
I do not own the copyright of the repository and the copyright belongs to Scott Meyers. The repository is only for personal use.