liminfo

C++ Reference

Free reference guide: C++ Reference

44 results

About C++ Reference

The C++ Reference is a comprehensive, searchable cheat sheet covering modern C++ from foundational syntax to advanced language features. The Basics section covers type deduction with auto (C++11), compile-time evaluation with constexpr, range-based for loops, scoped enumerations with enum class, namespaces, and the C++17 if statement with initializer (if (auto it = m.find(key); it != m.end())). The Pointers section covers raw pointer arithmetic, reference semantics, dynamic memory allocation with new/delete, the null pointer literal nullptr (C++11), and type-erased void* with static_cast. The Classes section covers object-oriented C++: access specifiers, member initializer lists, virtual functions with override, pure virtual interfaces, operator overloading, friend declarations, and the Rule of Five with copy constructors and move semantics.

The Templates section covers C++ generic programming: function templates, class templates for data structures like Stack<T>, template specialization for type-specific behavior, variadic templates with parameter pack expansion using fold expressions, and C++20 Concepts for type-constraining templates (template<Numeric T>). The STL section documents the most-used containers: std::vector with push_back/emplace_back/erase, ordered/unordered std::map with structured bindings for range-for, std::set with insert/count/erase, std::string with substr/find/replace, the algorithms header (sort, reverse, find, count), lambda expressions with capture lists, and std::pair/tuple with C++17 structured bindings (auto [a, b, c] = t).

The Smart Pointers section covers the RAII-based memory management tools that eliminate raw new/delete: std::unique_ptr for exclusive ownership (make_unique, move-only semantics), std::shared_ptr for shared ownership with reference counting (make_shared, use_count), and std::weak_ptr to break circular reference cycles (weak.lock()). The Concurrency section covers std::thread creation and join(), std::mutex with lock_guard for data race prevention, std::async with std::future for non-blocking task execution, and std::atomic for lock-free operations. The Modern C++ section covers C++17/20 features: std::optional, std::variant with std::visit, structured bindings, std::string_view, if constexpr for compile-time branching, and the C++20 ranges library with view pipelines.

Key Features

  • auto type deduction, constexpr compile-time evaluation, and range-based for loops (C++11)
  • Class definition with virtual/override, pure virtual interfaces, operator overloading, and move semantics
  • Template function/class, template specialization, variadic templates, and C++20 Concepts
  • STL containers: vector, map/unordered_map, set, string, and the algorithms library
  • Lambda expressions with capture lists ([factor], [&], [=]) for STL algorithm callbacks
  • Smart pointers: unique_ptr (exclusive), shared_ptr (reference counting), weak_ptr (cycle breaking)
  • Concurrency: std::thread, std::mutex with lock_guard, std::async/future, std::atomic
  • Modern C++17/20: optional, variant/visit, structured bindings, string_view, if constexpr, ranges

Frequently Asked Questions

What is the difference between unique_ptr and shared_ptr?

std::unique_ptr represents exclusive ownership — only one unique_ptr can point to an object at a time, and it cannot be copied (only moved). The object is destroyed when the unique_ptr goes out of scope. std::shared_ptr uses reference counting to allow multiple owners; the object is destroyed only when the last shared_ptr referencing it is destroyed or reset. unique_ptr has zero overhead over a raw pointer; shared_ptr has a small overhead for the control block. Use unique_ptr by default and shared_ptr only when shared ownership is genuinely needed.

What problem does std::weak_ptr solve?

std::weak_ptr solves the circular reference problem that arises with shared_ptr. If two objects hold shared_ptrs to each other, neither's reference count ever reaches zero, creating a memory leak. weak_ptr holds a non-owning reference that does not increment the reference count. To use the object, you call weak.lock(), which returns a shared_ptr if the object still exists or nullptr if it has been destroyed. A common pattern is using weak_ptr for back-pointers in parent-child relationships where the parent holds a shared_ptr to children.

What is the difference between const and constexpr?

const declares a variable or member function as read-only at runtime — the value can be computed at runtime and assigned once. constexpr declares that a variable or function must be evaluatable at compile time. A constexpr variable is implicitly const. A constexpr function can be called at compile time (when given compile-time arguments) to produce a compile-time constant, or at runtime like a regular function. Use constexpr for values that are truly fixed at compile time (array sizes, template arguments) to enable compiler optimizations.

When should I use a lambda instead of a named function?

Lambdas are best for short, context-specific operations that are only used in one place — particularly as callbacks to STL algorithms (std::sort, std::find_if, std::transform). The capture list [] lets you reference local variables: [&] captures all by reference, [=] captures all by value, and [factor] captures only the named variable by value. For complex operations reused in multiple places, a named function or functor is clearer. Lambdas stored in variables use std::function or auto.

What is move semantics and why does it matter for performance?

Move semantics (C++11) allow the internal resources of an object (like a heap-allocated buffer) to be transferred to a new object instead of copied. The source object is left in a valid but unspecified state. This eliminates expensive deep copies when returning large objects from functions or inserting them into containers. The move constructor is called with rvalue references (&&). std::move() casts an lvalue to an rvalue to explicitly request a move. std::vector, std::string, and all STL containers implement move semantics.

What is the difference between std::map and std::unordered_map?

std::map is a red-black tree that keeps keys in sorted order. Lookups, insertions, and deletions are O(log n). std::unordered_map is a hash table with O(1) average complexity for the same operations. Use std::map when you need keys sorted (e.g., for range queries with lower_bound), when keys lack a hash function, or when worst-case O(log n) is preferable to worst-case O(n) hash collisions. Use std::unordered_map for high-performance lookups where ordering is irrelevant.

What are C++20 Concepts and how do they improve template error messages?

C++20 Concepts are named compile-time predicates that constrain template type parameters. For example: template<typename T> concept Numeric = std::is_arithmetic_v<T>; defines a concept that only accepts arithmetic types. Using template<Numeric T> instead of template<typename T> makes the constraint explicit in the code and causes the compiler to emit a clear error at the call site when the type does not satisfy the concept, rather than the notoriously cryptic substitution failure errors from unconstrained templates.

What are structured bindings and when should I use them?

Structured bindings (C++17) allow you to unpack a struct, std::pair, std::tuple, or array into named variables in a single declaration: auto [key, val] = *map.begin(). They are most useful in range-for loops over maps (for (const auto& [k, v] : m)) and when returning multiple values via tuple or struct. They replace verbose std::get<0>(t) / pair.first / pair.second code. The bound names are references to the original elements unless the binding is declared auto (copy) vs auto& (reference).