Living document of C++ notes, books

This is a living document of my selected notes on modern C++ best practices. Including, but not limited to, notes from books I own, guidelines, and best idiomatic practices.

I'd like to first mention the kickstarter for me three years ago, Exploring C++20: The Programmer's Introduction to C++ 3rd edition, by Ray Lischner. C++ is frightening to engineers of any background. Exploring C++20 is broken down into pieces not only that anyone can understand, but with good intentions of someone who has battled against "the bad" parts of C++ and wants to forget them. The book allows you to skip C++'s dreadful history and write modern, well-written C++ today I felt qualified in the language after reading it alone.

At the bottom of this page, you will find a changelog addendum with the date and time of future changes.


Guidelines and Style Guides


Concepts, Notes, and Idioms of Good Modern C++

  • RAII - Resource acquisition is initialization (RAII) is an idiom that can help cope with resources in a safe way. The idiom is also known as constructor acquires, destructor releases (CADRe), and scope-based resource management (SBRM). RAII takes advantage of the symmetry of a class between its constructor and its corresponding destructor. We can allocate a resource in the constructor of a class, and we can deallocate it in the destructor. If we create such a class as a template, it can be used for different types of resources

  • Smart pointers - std::unique_ptr<T>, std::shared_ptr<T>, std::weak_ptr<T>

    • std::shared_ptr<T> and std::weak_ptr<T> are thread-safe by design.
  • std::atomic<T> in C++20

    • In computer science and software development, an atomic operation is a compound of single operations that can be seen as one undividable logical unit. This means that they can only be successful or fail as a whole. Atomic operations play an important role in database changes (so-called transaction safety), as well as in the implementation of locking mechanisms to avoid data races in parallel programming
  • Prefer std::jthread and joinable threads

    • The std::thread class requires the join() method be called explicitly to wait for the thread to finish. This can lead to programming errors. The C++20 standard provides a new thread class, called std::jthread, that solves this inconvenience
  • In modern C++, avoid all explicit use of new and delete

  • Take advantage of Boost

  • Prefer immutable data to mutable data

  • Write code well by default

  • Global scope using directive such as using namespace std;Never ever do this. Ever.

  • Prefer Uniform Initialization

  • Design to enable optimizations (by the compiler)

  • Use static_assert for compile-time assertion checks

  • std::move<T> and &&type rvalue references for move semantics

  • Use empty namespace instead of global static declarations

    • detail or internal namespace for implementation details
  • Data members should be private by default

    • Always keep data members private, and provide access only through member functions. See OCP "Closed for modification, open for extension" open-closed principle

    • Avoid trivial getters and setters

      • There is no point in making data private if you’re simply going to
        expose it through other means.
      • Trivial getters and setters add nothing to an interface.
      • Nontrivial setters should preserve class invariants.
      • Nouns and verbs provide superior function identifiers that better reflect
        the abstraction
      • Unrelated data without class invariants can be bundled into a struct
    • A class invariant is a condition that must hold for all valid instances of a class

  • Any class that has virtual functions must declare its destructor to be virtual
    too


Books

  • Exploring C++20: The Programmer's Introduction to C++ 3rd edition
  • Effective C++, 3rd edition
  • More Effective C++
  • Clean C++20

Honorable Mentions:

  • C++ Concurrency in Action
  • Functional Programming in C++

Addendum