All Projects → muqsitnawaz → Modern Cpp Cheatsheet

muqsitnawaz / Modern Cpp Cheatsheet

Licence: mit
Cheatsheet for best practices of Modern C++ (taken from Effective Modern C++)

Programming Languages

cpp11
221 projects
cpp14
131 projects

Projects that are alternatives of or similar to Modern Cpp Cheatsheet

Nginx Admins Handbook
How to improve NGINX performance, security, and other important things.
Stars: ✭ 12,463 (+8208.67%)
Mutual labels:  cheatsheet, best-practices
Tensorflow Cheatsheet
My personal reference for Tensorflow
Stars: ✭ 147 (-2%)
Mutual labels:  cheatsheet
Wireshark Cheatsheet
Wireshark Cheat Sheet
Stars: ✭ 131 (-12.67%)
Mutual labels:  cheatsheet
Android Modular Architecture
📚 Sample Android Components Architecture on a modular word focused on the scalability, testability and maintainability written in Kotlin, following best practices using Jetpack.
Stars: ✭ 2,048 (+1265.33%)
Mutual labels:  best-practices
State Of The Art Shitcode
💩State-of-the-art shitcode principles your project should follow to call it a proper shitcode
Stars: ✭ 2,207 (+1371.33%)
Mutual labels:  best-practices
Welcome
Information on joining the government community — a collaborative community for sharing best practices in furtherance of open source, open data, and open government efforts.
Stars: ✭ 143 (-4.67%)
Mutual labels:  best-practices
Kotlin Quick Guide
A quick guide to Kotlin for developers.
Stars: ✭ 127 (-15.33%)
Mutual labels:  cheatsheet
Forecasting
Time Series Forecasting Best Practices & Examples
Stars: ✭ 2,123 (+1315.33%)
Mutual labels:  best-practices
Vue Master Class
🗂 Source code for The Vue 2 Master Class
Stars: ✭ 147 (-2%)
Mutual labels:  best-practices
Cheats.rs
Rust Language Cheat Sheet - https://cheats.rs
Stars: ✭ 2,263 (+1408.67%)
Mutual labels:  cheatsheet
Php Programming Best Practices
Referencia para los desarrolladores de Tiendanube y para la comunidad de PHP.
Stars: ✭ 138 (-8%)
Mutual labels:  best-practices
Cheat Sheets
🌟 All the cheat-sheets mentioned on my blog in pdf format
Stars: ✭ 136 (-9.33%)
Mutual labels:  cheatsheet
Dagger2
Kotlin Dagger2 example project
Stars: ✭ 145 (-3.33%)
Mutual labels:  best-practices
Nginx Tuning
NGINX tuning for best performance
Stars: ✭ 1,900 (+1166.67%)
Mutual labels:  best-practices
Nn Template
Generic template to bootstrap your PyTorch project with PyTorch Lightning, Hydra, W&B, and DVC.
Stars: ✭ 145 (-3.33%)
Mutual labels:  best-practices
Git Good Commit
Git hook to help you write good commit messages, with no external dependencies.
Stars: ✭ 128 (-14.67%)
Mutual labels:  best-practices
Abstract Algebra Cheatsheet
📗 A visualization of key structures in abstract algebra.
Stars: ✭ 137 (-8.67%)
Mutual labels:  cheatsheet
Generator Jekyll Starter Kit
🚀 Jekyll Progressive Web App Generator.
Stars: ✭ 139 (-7.33%)
Mutual labels:  best-practices
Privilege Escalation
This cheasheet is aimed at the CTF Players and Beginners to help them understand the fundamentals of Privilege Escalation with examples.
Stars: ✭ 2,117 (+1311.33%)
Mutual labels:  cheatsheet
Stanford Cs 221 Artificial Intelligence
VIP cheatsheets for Stanford's CS 221 Artificial Intelligence
Stars: ✭ 1,923 (+1182%)
Mutual labels:  cheatsheet

Effective Modern C++ Cheatsheet

Shorthands

  1. ref(s): reference(s)
  2. op(s): operation(s)

Terms

  1. lvalue: typically an expression whose address can be taken e.g a variable name (auto x = 10;)
  2. rvalue: an expression whose address cannot be taken in C++ i.e before C++11 e.g literal types (10)
  3. lvalue-ref(erence): reference to an lvalue type typically denoted by & e.g auto& lvalue_ref = x;
  4. rvalue-ref(erence): reference to an rvalue type typically denoted by && e.g auto&& rvalue_ref = 10;
  5. copy-operations: copy-construct from lvalues using copy-constructor and copy-assignment operator
  6. move-operations move-construct from rvalues using move-constructor and move-assignment operator
  7. arguments: expressions passed to a function call at call site (could be either lvalues or rvalues)
  8. parameters: lvalue names initialized by arguments passed to a function e.g x in void foo(int x);
  9. callable objects: objects supporting member operator() e.g functions, lambdas, std::function etc
  10. declarations: introduce names and types without details e.g class Widget;, void foo(int x);
  11. definitions: provide implementation details e.g class Widget { ... };, void foo(int x) { ... }

Chapter 1. Deducing Types

Item 1: Understand template type deduction

  • Deduced type of T doesn't always match that of the parameter (i.e ParamType) in template functions
  • For lvalue-refs/rvalue-refs, compiler ignores the reference-ness of an arg when deducing type of T
  • With universal-refs, type deduction always distinguishes between l-value and r-value argument types
  • With pass-by-value, reference-ness, const and volatile are ignored if present in the ParamType
  • Raw arrays [] and function types always decay to pointer types unless they initialize references

Item 2: Understand auto type deduction

  • auto plays the role of T while its type specifier (i.e including const and/or ref) as ParamType
  • For a braced initializer e.g {1, 2, 3}, auto always deduces std::initializer_list as its type
  • Corner case: auto as a callable return type uses template type deduction, not auto type deduction

Item 3: Understand decltype

  • decltype, typically used in function templates, determines a variable or an expression's type
  • decltype(auto), unlike auto, includes ref-ness when used in the return type of a callable
  • Corner case: decltype on lvalue expression (except lvalue-names) yields lvalue-refs not lvalues

Item 4: How to view deduced types?

  • You can update your code so that it leads to a compilation failure, you will see the type in diagnostics
  • std::type_info::name (and typeid()) depends upon compiler; use Boost.TypeIndex library instead

Chapter 2. auto

Item 5: Prefer auto declarations

  • auto prevents uninitialized variables and verbose declarations (e.g std::unordered_map<T>::key_type)
  • Use auto especially when declaring lambdas to directly hold closures unlike std::function

Item 6: How to fix undesired auto type deduction?

  • Use auto with static_cast (a.k.a explicitly typed initializer idiom) to enforce correct types
  • Never use auto directly with invisible proxy classes such as std::vector<bool>::reference

Chapter 3. Moving to Modern C++

Item 7: Distinguish between () and {} (aka braced/uniform initializer) when creating objects

  • Braced initializer i.e {} prevents narrowing conversions and most vexing parse while () doesn't
  • During overload-resolution, std::initializer_list version is always preferred for {} types
  • Corner case: std::vector<int> v{10, 20} creates a vector with 10 and 20, not 10 ints initialized to 20.

Item 8: Prefer nullptr to 0 and NULL

  • Don't use 0 or NULL, use nullptr of type nullptr_t which represents pointers of all types!

Item 9: Prefer alias declarations to typedefs

  • Alias declarations (declared with using keyword) support templatization while typedefs don't
  • Alias declarations avoid 1) ::type suffix 2) typename prefix when referring to other typedefs

Item 10: Prefer scoped enums to unscoped enums

  • Use enum class instead of enum to limit scope of an enum members to just inside the enum
  • enum classes use int by default, prevent implicit conversions and permit forward declarations

Item 11: Prefer public-deleted functions to private-undefined versions

  • Always make unwanted functions (such as copy-operations for move-only types) public and delete

Item 12: Always declare overriding functions override

  • Declare overriding functions in derived types override; use final to prevent further inheritance

Item 13: Always prefer const_iterators to iterators

  • Prefer const_iterators to iterators for all STL containers e.g cbegin instead of begin
  • For max generic code, don't assume the existence of member cbegin; use std::begin instead

Item 14: Declare functions noexcept if they won't emit exceptions

  • Declare functions noexcept when they don't emit exceptions such as functions with wide contracts
  • Always use noexcept for move-operations, swap functions and memory allocation/deallocation
  • When a noexcept function emits an exception: stack is possibly wound and program is terminated

Item 15: Use constexpr whenever possible

  • constexpr objects are always const and usable in compile-time evaluations e.g template parameters
  • constexpr functions produce results at compile-time only if all of their args are known at compile-time
  • constexpr objects and functions can be used in a wider context i.e compile-time as well as runtime

Item 16: Make const member functions thread-safe

  • Make member functions of a type const as well as thread-safe if they do not modify its members
  • For synchronization issues, consider std::atomic first and then move to std::mutex if required

Item 17: Understand when your compiler generates special member functions

  • Compiler generates a default constructor only if the class type declares no constructors at all
  • Declaring destructor and/or copy ops disables the generation of default move ops and vice versa
  • Copy assignment operator is generated if: 1) not already declared 2) no move op is declared

Chapter 4. Smart Pointers

Item 18: Use std::unique_ptr for exclusive-ownership of resource management

  • std::unique_ptr owns what it points to, is fast as raw pointer (*) and supports custom deleters
  • Conversion to a std::shared_ptr is easy, therefore factory functions should always return std::unique_ptr
  • std::array, std::vector and std::string are generally better choices than using raw arrays []

Item 19: Use std::shared_ptr for shared-ownership resource management

  • std::shared_ptr points to an object with shared ownership but doesn't actually own the object
  • std::shared_ptr stores/updates metadata on heap and can be up to 2x slower than std::unique_ptr
  • Unless you want custom deleters, prefer std::make_shared<T> for creating shared pointers
  • Don't create multiple std::shared_ptrs from a single raw pointer; it leads to undefined behavior
  • For std::shared_ptr to this, always inherit your class type from std::enable_shared_from_this

Item 20: Use std::weak_ptr for std::shared_ptr-like pointers that can dangle

  • std::weak_ptr operates with the possibility that the object it points to might have been destroyed
  • std::weak_ptr::lock() returns a std::shared_ptr, but a nullptr for destroyed objects only
  • std::weak_ptr is typically used for caching, observer lists and prevention of shared pointers cycles

Item 21: Prefer make functions (i.e std::make_unique and std::make_shared) to direct use of new

  • Use make functions to remove source code duplication, improve exception safety and performance
  • When using new (in cases below), prevent memory leaks by immediately passing it to a smart pointer!
  • You must use new when 1) specifying custom deleters 2) pointed-to object is a braced initializer
  • Use new when std::weak_ptrs outlive their std::shared_ptrs to avoid memory de-allocation delays

Item 22: When using Pimpl idiom, define special member functions in an implementation file

  • Pimpl idiom puts members of a type inside an impl type (struct Impl) and stores a pointer to it
  • Use std::unique_ptr<Impl> and always implement your destructor and copy/move ops in an impl file

Chapter 5. Rvalue references, move semantics and perfect forwarding

  • Move semantics aim to replace expensive copy ops with the cheaper move ops when applicable
  • Perfect forwarding forwards a function's args to other functions parameters while preserving types

Item 23: Understand std::move and std::forward

  • std::move performs an unconditional cast on lvalues to rvalues; you can then perform move ops
  • std::forward casts its input arg to an rvalue only if the arg is bound to an rvalue name

Item 24: Distinguish universal-refs from rvalue-refs

  • Universal-refs (i.e T&& and auto&&) always cast lvalues to lvalue-refs and rvalues to rvalue-refs
  • For universal-ref parameters, auto/template type deduction must occur and they must be non-const

Item 25: Understand when to use std::move and std::forward

  • Universal references are usually a better choice than overloading functions for lvalues and rvalues
  • Apply std::move on rvalue refs and std::forward on universal-refs last time each is used
  • Similarly, also apply std::move or std::forward accordingly when returning by value from functions
  • Never return local objects from functions with std::move! It can prevent return value optimization (RVO)

Item 26: Avoid overloading on universal-references

  • Universal-refs should be used when client's code could pass either lvalue refs or rvalue refs
  • Functions overloaded on universal-refs typically get called more often than expected - avoid them!
  • Avoid perf-forwarding constructors because they can hijack copy/move ops for non-const types

Item 27: Alternatives to overloading universal-references

  • Ref-to-const works but is less efficient while pass-by-value works but use only for copyable types
  • Tag dispatching uses an additional parameter type called tag (e.g std::is_integral) to aid in matching
  • Templates using std::enable_if_t and std::decay_t work well for universal-refs and they read nicely
  • Universal-refs offer efficiency advantages although they sometimes suffer from usability disadvantages

Item 28: Understand reference collapsing

  • Reference collapsing converts & && to & (i.e lvalue ref) and && && to && (i.e rvalue ref)
  • Reference collapsing occurs in template and auto type deductions, alias declarations and decltype

Item 29: Assume that move operations are not present, not cheap, and not used

  • Generally, moving objects is usually much cheaper then copying them e.g heap-based STL containers
  • For some types e.g std::array and std::string (with SSO), copying them can be just as efficient

Item 30: Be aware of failure cases of perfect forwarding

  • Perf-forwarding fails when template type deduction fails or deduces wrong type for the arg passed
  • Fail cases: braced initializers and passing 0 or NULL (instead of nullptr) for null pointers
  • For integral static const data members, perfect-forwarding will fail if you're missing their definitions
  • For overloaded or template functions, avoid fail cases using static_cast to your desired type
  • Don't pass bitfields directly to perfect-forwarding functions; use static_cast to an lvalue first

Chapter 6. Lambda Expressions

Item 31: Avoid default capture modes

  • Avoid default & or = captures for lambdas because they can easily lead to dangling references
  • Fail cases: & when they outlive the objects captured, = for member types when they outlive this
  • static types are always captured by-reference even though default capture mode could be by-value

Item 32: Use init-capture (aka generalized lambda captures) to move objects into (lambda) closures

  • Init-capture allows you to initialize types (e.g variables) inside a lambda capture expression

Item 33: Use decltype on auto&& parameters for std::forward

  • Use decltype on auto&& parameters when using std::forward for forwarding them to other functions
  • This case will typically occur when you are implementing perfect-forwarding using auto type deduction

Item 34: Prefer lambdas to std::bind

  • Always prefer init capture based lambdas (aka generalized lambdas) instead of using std::bind

Chapter 7. Concurrency API

Item 35: Prefer std::async (i.e task-based programming) to std::thread (i.e thread-based)

  • When using std::threads, you almost always need to handle scheduling and oversubscription issues
  • Using std::async (aka task) with default launch policy handles most of the corner cases for you

Item 36: Specify std::launch::async for truly asynchronous tasks

  • std::async's default launch policy can run either async (in new thread) or sync (upon .get() call)
  • If you get std::future_status::deferred on .wait_for(), call .get() to run the given task

Item 37: Always make std::threads unjoinable on all paths

  • Avoid program termination by calling .join() or .detach() on an std::thread before it destructs!
  • Calling .join() can lead to performance anomalies while .detach() leads to undefined behavior

Item 38: Be aware of varying destructor behavior of thread handle

  • std::future blocks in destructor if policy is std::launch::async by calling an implicit join
  • std::shared_future blocks when, additionally, the given shared future is the last copy in scope
  • std::packaged_task doesn't need a destructor policy but the underlying std::thread (running it) does

Item 39: Consider std::futures of void type for one-shot communication (comm.)

  • For simple comm., std::condition_variable, std::mutex and std::lock_guard is an overkill
  • Use std::future<void> and std::promise for one-time communication between two threads

Item 40: Use std::atomic for concurrency and volatile for special memory

  • Use std::atomic guarantees thread-safety for shared memory while volatile specifies special memory
  • std::atomic prevents reordering of reads/write operations but permits elimination of redundant reads/writes
  • volatile specifies special memory (e.g for memory mapped variables) which permits redundant reads/writes

Chapter 8. Tweaks

Item 41: When to use pass-by-value for functions parameters

  • Consider pass-by-value for parameters if and only if they are always copied and are cheap to move
  • Prefer rvalue-ref parameters for move-only types to limit copying to exactly one move operation
  • Never use pass-by-value for base class parameter types because it leads to the slicing problem

Item 42: Choose emplacement instead of insertion

  • Use .emplace versions instead of .push/.insert to avoid temp copies when adding to STL containers
  • When value being added uses assignment, .push/.insert work just as well as the .emplace versions
  • For containers of resource-managing types e.g smart pointers, .push/.insert can prevent memory leaks
  • Be careful when using .emplace functions because the args passed can invoke explicit constructors
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].