Build process
For an introduction to the build process, see The C++ Build Process Explained and the related HackerNews thread.
For a deeper explanation, see The Bits Between the Bits: How We Get to main().
For a real-time visualisation of the build process, see this post.
Best practices:
- Use a package manager (e.g. conan or vcpkg)
- Use CMake with Ninja (for CMake best practices, see Professional CMake or Pragmatic CMake)
- Strict compiler settings: at least
-Wall -Wextra -Werror, preferably also -Wpedantic -Wcast-align -Wno-unused -Wshadow -Woverloaded-virtual, and ideally with -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion - Static analysis: linters, formatters (e.g.
clang-tidy and clang-format) - Dynamic analysis: sanitizers, at least ASan and UBSan (e.g.
g++ -fsanitize=address,undefined -g -O1)
Learning resources
For a discussion on C++ learning resources, see this HackerNews discussion or Reddit thread.
Below are some highlights.
Books
Tutorials
Videos
Miscellaneous
- cplusplus.com, community tutorials, forum and blog posts
- Cheat sheet with HackerNews thread
- Well-written C++ repos: nlohmann/json
- Example best-practices repository bemanproject/exemplar
- C++ best practices (Jason Turner)
- It’s Complicated (Kate Gregory, Meeting C++ 2017 Keynote)
- 10 Core Guidelines You Need to Start Using Now (Kate Gregory, CppCon 2017)
- Undefined Behavior in C++: What Every Programmer Should Know and Fear (Fedor Pikus, CppCon 2023)
- Crafting the Code You Don’t Write: Sculpting Software in an AI World (Daisy Hollman, CppCon 2025)
- Learning To Stop Writing C++ Code (and Why You Won’t Miss It) (Daisly Holman, ACCU 2025)
- You’ve just inherited a legacy C++ codebase, now what?, great blog post on working with a legacy C++ code base, but most tips apply to any language; also see the related HackerNews thread and the blog post on how to ignore large formatting changes using .git-blame-ignore-revs
- cppreference.com, language reference
- C++ Insights and Compiler Explorer to better understand the compiled code and how the compiler works
- ISO C++ User Groups to find user groups around the world
- Low-latency C++ patterns
- C++ to Rust Phrasebook
- Comprehensive C++ Hashmap Benchmarks 2022
C++ shortcomings and its future
- C++26 is done: ISO C++ standards meeting Trip Report HackerNews thread
- Why I don’t spend time with Modern C++ anymore
- Linus Torvalds on C++
- C++ is an absolute blast
- Modern C++ Won’t Save Us
- “Modern” C++ Lamentations
- All C++20 core language features with examples
- The two factions of C++, HackerNews thread
- Matt Godbolt sold me on Rust by showing me C++
- It’s time to halt starting any new projects in C/C++, discussion based on the original tweet
- Rust Devs Think We’re Hopeless; Let’s Prove Them Wrong (with C++ Memory Leaks)!
- Lessons Learnt from a Rust Rewrite
- Comparing with Rust: “In my experience, C++ is a much more complicated language. The 8 ways to initialize something, the 5 types of values (xvalues etc.), inconsistent formatting conventions, inconsistent naming conventions, the rule of 5, exceptions, always remembering to check
this != other when doing a move assignment operator, perfect forwarding, SFINAE, workarounds for not having a great equivalent to traits, etc. Part of knowing the language is also knowing the conventions on top that are necessary in order to write it more safely and faster (if your move constructor is not noexcept it’ll cause copies to occur when growing a vector of that object), and learning the many non-ideal competing ways that people do things, like error handling.” (HackerNews comment)
My notes
Some loose notes from reading and working through some tutorials:
- Disable function overloading and implicit conversions, for example using the
explicit keyword and strict clang settings (cppcoreguidelines-explicit-virtual-functions, google-explicit-constructor, cppcoreguidelines-narrowing-conversions) - Use
const almost everywhere, for input arguments to functions and when initializing variables (see John Carmack’s tweet and Jason Turner’s guide) - Use
constexpr (or consteval) for everything that can be computed at compile time - Use
[nodiscard] for not forgetting about a return value - Use
noexcept for performance optimization