C++ Cheatsheet — Quick Reference
A concise C++17/20 cheatsheet covering syntax, the standard library, classes, templates, and the most common idioms — roughly 80% of everyday scenarios.
C++ C++17 / C++20
ISO C++ (GCC / Clang / MSVC) · Multi-paradigm (OOP · generic · functional) · Static · strong · nominal
Recommended Learning Path
Start with "Hello World and Build Setup" to get a clean compile/run cycle under your belt. Then move through variables, types, control flow, and functions; pick up the standard containers (vector, map) and strings; learn RAII and smart pointers (the memory chapter); then OOP and templates; finally dip into threads, networking, regex, and the build tools as needed. The FAQ chapter is the place to revisit when something surprises you.
1.Hello World and Build Setup
Compile, run, and organize a C++ program from scratch: toolchain, command-line arguments, multiple files, and C++20 modules.
Minimal program
Every C++ program starts executing at main(); returning 0 indicates success. std::cout is the standard output stream, fed via operator<<.
Compile and run
Compile with g++ or clang++: -std selects the C++ standard, -Wall -Wextra enables warnings, -o names the output binary; run with ./app.
CMake build
CMake is the mainstream cross-platform build system: CMakeLists.txt declares the project and targets, -B sets the build directory, --build triggers compilation; outputs land under build/.
Command-line arguments
main's argc is the argument count, argv is the argument array, and argv[0] is always the program name. User arguments start at argv[1].
Exit code
main's return value becomes the process exit code: 0 means success, non-zero indicates an error category. EXIT_SUCCESS / EXIT_FAILURE read better.
Multi-file build
Declarations live in headers (#pragma once guards re-inclusion), definitions in .cpp files, used via #include. Compile all .cpp files together to link.
C++20 modules
Modules replace headers: export module declares a module, export exposes symbols, import pulls them in — faster builds, no macro pollution, but still maturing.
Namespace
Namespaces organize symbols to avoid clashes. Qualify with geo::area, or prefer precise using-declarations like using std::cout over using namespace ...
2.Variables and Constants
Declarations and type deduction, const/constexpr, references, structured bindings, scope, and C++-style casts.
auto type deduction
auto deduces the type from the initializer and must be initialized immediately. Deduction strips references and top-level const; write const auto& explicitly when needed.
const and constexpr
const marks a value as immutable; constexpr guarantees compile-time evaluation, usable for array sizes and template arguments. C++20 constexpr functions can hold more logic.
References
A reference is an alias for an existing object: it must be initialized and always refers to the same object. Passing by reference avoids copies and lets the callee modify the original.
Structured bindings
C++17 destructures pair/tuple/struct/array into named variables. Unpacking key/value while iterating a map is the most common use case.
Inline variables
Before C++17, non-constexpr globals in headers caused multiple-definition errors; inline variables let multiple translation units share the same object.
mutable members
mutable members can be modified inside const member functions — typically used for caches, call counters, or mutexes whose change doesn't alter the object's logical state.
decltype
decltype yields the declared type of an expression. decltype((x)) (with extra parens) deduces a reference — a common trap; trailing return types are handy in templates.
Scope and shadowing
C++ allows inner scopes to shadow outer names. Avoid shadowing globals — use ::n to reach the global explicitly, though it hurts readability.
Literal suffixes
Suffixes fix literal types: LL for long long, f for float, s for std::string. The 0b binary prefix and ' digit separator boost readability.
C++-style casts
static_cast for compile-time semantic conversions; dynamic_cast for runtime polymorphic casts (pointer failure returns nullptr, reference throws bad_cast); const_cast drops const but only when the original object is non-const.
3.Data Types
Built-in types, enums, structs, template types, and modern utility types like std::optional, std::variant, and std::any.
Built-in types
Built-in types are distinguished by size and signedness. <cstdint> provides fixed-width types like int32_t/uint64_t with consistent cross-platform behavior.
enum class
enum class is safer than a plain enum: values must be qualified, and there is no implicit conversion to int — preventing name leakage and accidental integer use.
struct
struct defaults members to public and is great for passive data bundles. With default member initializers, brace-init creates a fully set-up object in one line.
union
union shares one block of memory among several members, holding only one at a time. In standard C++ prefer std::variant; union is mostly for low-level memory reuse.
Template types
Templates parameterize types; the compiler instantiates a version per used type — the foundation of generic programming and the standard containers.
Type aliases
using declarations for type aliases are clearer than typedef and support template aliases. An alias doesn't create a new type — just another name for the same type.
optional
std::optional represents "may or may not have a value" returns, replacing sentinels or out-parameters. Use it in a boolean context to test presence; * extracts the value.
variant
std::variant is a type-safe union holding exactly one of a fixed list of types. std::get<T> returns by value (throws bad_variant_access on type mismatch), std::get_if<T> returns a pointer without throwing.
std::any
std::any holds any copyable type and can be cast back at runtime — handy for heterogeneous containers or plugin arguments, but it has type-erasure cost; prefer variant when possible.
pair and tuple
pair holds two values, tuple any number. Structured bindings unpack elements into named variables — far more readable than indexing std::get.
4.Pointers and Arrays
Raw pointers, smart pointers, arrays, and references — who owns the memory and which to use when.
Raw pointer
A raw pointer stores an object's address: * dereferences, & takes the address. Raw pointers don't own memory; pair them with new/delete or hand them to a smart pointer.
Pointer and array
An array name decays to a pointer to its first element in expressions: p+i is address arithmetic, *(p+i) is dereference. This is C-inherited low-level behavior.
nullptr
nullptr is a type-safe null pointer constant, replacing NULL or 0. Dereferencing a null pointer is undefined behavior — always check before use.
new and delete
new allocates heap memory and returns a pointer; delete frees it; new[] must pair with delete[]. Manual management leaks easily — prefer RAII containers or smart pointers.
unique_ptr
unique_ptr has exclusive ownership and deletes automatically at scope exit. make_unique is exception-safe; ownership is transferred via std::move; copying is forbidden.
shared_ptr
shared_ptr shares ownership via a reference count; the object is freed when the count hits zero. Avoid cycles — use weak_ptr to break them.
weak_ptr
weak_ptr doesn't own the object and doesn't affect the count; lock() temporarily promotes it to shared_ptr (empty if the object was already freed). Ideal for breaking cycles.
Reference vs pointer
References are syntactically lighter and guaranteed non-null — prefer them for parameters; use a pointer when the argument might be absent or might be reseated.
const pointers
Read right-to-left: int* const is a const pointer to int; const int* is a pointer to const int. Mixing them up is a classic declaration mistake.
void*
void* is a pointer to memory of unknown type; you must cast back to a concrete type before dereferencing. C APIs use it for opaque data; avoid it in C++.
5.Control Flow
if/for/while/switch and the init-statement form of if/switch introduced in C++17.
if / else
if/else selects an execution path by condition. From C++17 on, if can carry an init-statement (see if-with-initializer).
for loop
The classic for loop has init / condition / step. Prefer ++i in counting loops — semantically it avoids one temporary copy.
range-for
Range-for (C++11) iterates container elements and avoids manual index and bounds bugs. Use auto& to modify, const auto& to read.
while / do-while
while checks the condition first; do-while runs the body at least once. Both fit cases where the iteration count is unknown and depends on runtime state.
switch / case
switch dispatches on an integer or enum value and reads more clearly than an if-chain. Every case must break (or return) or control falls through to the next label.
break and continue
continue skips the rest of the current iteration; break exits the entire loop. In nested loops, a label can let goto jump out of multiple levels.
if with initializer
From C++17 on, if/switch can declare an init variable scoped to the branch, avoiding leakage into the enclosing scope — the idiomatic find-then-check form.
Ternary operator
The ternary operator expresses if/else assignment in one line. Both branches must be compatible types; for complex logic a plain if is clearer.
goto label
goto jumps directly to a label, breaking structured control flow — almost always replaceable by a flag or return. The only defensible use is breaking out of nested loops.
6.Functions and Lambdas
Declarations and definitions, overloading, parameter passing, lambdas and function templates, variadic templates, and recursion.
Declare and define
A declaration tells the compiler the signature; a definition provides the body. Declarations can appear in headers many times; definitions must be unique per program.
Function overloading
Overloading lets the same name dispatch by argument type; the compiler picks the best match. Return type alone cannot distinguish overloads.
Default arguments
Default arguments let the caller omit trailing arguments. They must be supplied contiguously from the right; provide them in only one of the declaration or definition.
Parameter passing
Pass-by-value copies the whole object; const& avoids the copy and forbids mutation; & allows modification; && (rvalue reference) receives temporaries so resources can be moved out.
Return value
Modern C++ returns temporaries via RVO/NRVO for zero copies. Never return the address or reference of a local — that's a dangling reference.
Lambda expressions
A lambda is an anonymous function object: capture list [] + parameters + body. Combined with <algorithm> it's the mainstream way to write callbacks and comparators.
Lambda captures
[=] captures everything by value, [&] by reference, [x] captures specific names. When capturing by reference, make sure the original outlives the lambda.
Function templates
Function templates are instantiated per argument type deduced at the call site — one implementation serves all types. Types must support the operators used.
Variadic templates
A parameter pack ...Args accepts any number of arguments; a fold expression (args + ...) applies a binary operator across the pack — a modern replacement for printf-style variadic functions.
Recursion
Recursion is a function calling itself; a base case terminates it. Deep recursion eats the call stack — watch for overflow and overlapping subproblems.
7.Strings
std::string basics, concatenation, search/replace, formatting, string streams, and number/string conversions.
std::string basics
std::string is a mutable, growable character container with automatic memory management. Indexing via [] past the end is undefined; at() throws instead.
String literals
A "..." literal defaults to const char*; the s suffix gives a std::string; string_view is a read-only non-owning view, perfect for parameter passing without copies.
Concatenation and reserve
For heavy concatenation, reserve up front to avoid repeated reallocation. Chaining + creates temporaries — in hot paths, reuse a buffer.
Substring and search
substr(pos, len) extracts a substring; find/rfind locate the first match, returning std::string::npos when not found.
Replace
Member replace(pos, len, str) replaces by position; <algorithm>'s std::replace swaps every matching character by value.
Formatted output
std::format (C++20) formats via placeholders with compile-time argument count checks — replacing sprintf and cout concatenation. :04d zero-pads; :.2f keeps two decimals.
stringstream
stringstream treats an in-memory string as a stream: ostringstream builds, istringstream parses with >> — a flexible tool for formatting and reverse-parsing.
String/number conversion
stoi/stod/stoll parse strings into numbers; std::to_string converts back. Failures and overflows throw std::invalid_argument / out_of_range.
Raw string literals
Inside R"(...)" the backslash is literal — perfect for regexes, paths, and multi-line text. If the body contains )", use a custom delimiter: R"tag(...)tag".
Iterate characters
Range-for is the cleanest way to walk characters one by one; use char& to mutate. The begin/end iterator form plays nicely with legacy code and the algorithm library.
8.Containers and Algorithms
vector/array/map/set, priority queues, plus sorting, searching, and ranges algorithms.
vector
vector is a dynamic array: O(1) push/pop at the back, O(1) random access. If you push_back a lot, reserve first; avoid front insertion (O(n)).
std::array
std::array is the modern wrapper for a fixed-size stack array: it has size()/begin()/end() and plays well with the algorithm library. Use array for fixed size, vector for variable size.
map
std::map is an ordered key/value store (red-black tree): keys stay sorted, lookup is O(log n). When order doesn't matter, use unordered_map (average O(1)).
unordered_map
unordered_map is a hash table with average O(1) lookup and no ordering. operator[] inserts a default value for missing keys — for pure queries use find or at().
set
set holds an ordered, deduplicated collection; insert/erase/find are all O(log n); unordered_set is the hash version (unordered, O(1)). contains() (C++20) tests membership.
deque and list
deque gives O(1) insertion/removal at both ends; list gives O(1) middle insertion but O(n) random access. Pick the container that matches your access pattern.
priority_queue (heap)
priority_queue is a heap: push is O(log n), top is O(1). Default is max-heap; for min-heap supply a greater comparator.
Sort
std::sort sorts a random-access container in-place in O(n log n). A custom comparator returns whether a should come before b. For list, use its member sort().
Search
Use std::find for linear lookup on unsorted containers; binary_search/lower_bound for O(log n) on sorted ones. find returns an iterator; compare against end() to detect a hit.
ranges pipeline
C++20 ranges compose lazy views via |: filter selects, transform maps, with no copies or allocations — sequence processing as an expression.
9.Dynamic Memory and Ownership
RAII, move semantics, smart pointer trade-offs, and exception safety — the core of C++ resource management.
RAII
RAII ties resource acquisition to the constructor and release to the destructor — resources are freed automatically on destruction, with no manual cleanup and full exception safety.
make_unique
make_unique builds a unique_ptr in one step that fuses new and construction — even if construction throws, no raw pointer leaks. Array form: make_unique<T[]>(n).
make_shared
make_shared allocates the object and the control block together — one allocation instead of two. From C++20 the control block doesn't waste any size alignment.
Move semantics
std::move casts an lvalue to an rvalue reference, enabling move instead of copy — internal pointers transfer over, the source is left empty, no deep copy of large arrays.
Move constructor
A move constructor steals the source's resources and leaves it empty — much faster than copy. Mark it noexcept so vector reallocation prefers move over copy.
Return value optimization
The compiler elides redundant copy/move constructions and builds the return value directly in the caller's storage. C++17 guarantees zero-copy for prvalue returns.
Break cycles with weak_ptr
In parent/child trees, the parent holds shared_ptr while the child back-references the parent with weak_ptr — otherwise they keep each other alive forever. lock() safely promotes to shared_ptr.
noexcept
noexcept declares a function non-throwing — vector uses it to decide between move and copy during reallocation. If it throws anyway, std::terminate is called; only mark it when you're sure.
Manual leaks
Manual new/delete leaks if an exception fires or an early return happens. RAII (smart pointers / containers) hands cleanup to the destructor — exception-safe.
10.Object-Oriented Programming
Classes, access control, constructors and destructors, inheritance and polymorphism, pure-virtual interfaces, friend, and operator overloading.
Class definition
class bundles data with the operations on it. Members are private by default (the opposite of struct); access them via public methods.
Access specifiers
public: visible to everyone. protected: visible to the class and its derivatives. private: visible only to the class. Defaults are private for class, public for struct.
Constructor
Constructors share the class name; use the initializer list : x(x_) for members (more efficient than assigning in the body). The parameterless one is the default constructor.
Delegating constructor
A delegating constructor hands off to another constructor in the same class — no repeated initialization logic. The delegated target must already be declared.
Destructor
The destructor runs on object teardown — it's where RAII releases resources. A base-class destructor must be virtual or deleting a derived object via base pointer only destroys the base part.
Inheritance
Inheritance lets a derived class reuse the base's interface and implementation. Calling a virtual function through a base pointer/reference triggers runtime polymorphism.
virtual and abstract class
virtual marks overridable functions; pure-virtual (=0) makes the class abstract and uninstantiable. A class with any virtual function should also have a virtual destructor.
override and final
override asserts "I'm overriding a base virtual" — a mismatched signature becomes a compile error instead of silently creating a new function. final forbids further overrides.
Pure-virtual interface
A pure-virtual function (= 0) defines an interface without an implementation; a class with one is abstract, so derived classes must implement it to be instantiable — much like a Java interface.
friend
friend grants specified classes or functions access to private members, breaking encapsulation. Use it sparingly, in tightly-coupled scenarios (operator overloading, internal iterators).
Operator overloading
Operator overloading lets your types support +, -, <<, etc. Keep semantics intuitive — + shouldn't mutate operands, << is for output — and don't overuse it, as readability suffers.
11.Error Handling
Exception catching, the standard exception hierarchy, custom exceptions, noexcept, and non-throwing paths via optional/expected.
try / catch
Exceptions thrown inside a try block are caught by a matching catch. Prefer catching std::exception& as the base, and split per concrete type when needed; uncaught exceptions unwind the call stack.
catch by reference
Catch by const& to preserve polymorphism with zero copies; catch by value and you'll slice (the derived part is cut off). catch(...) catches everything but loses type info.
Standard exception hierarchy
Standard exceptions derive from std::exception. Put specific catches first and the std::exception& fallback last — the most specific match wins.
Custom exception
Custom exceptions derive from std::runtime_error (or a sibling); using inherits the constructors, what() carries the message, and a base-class catch in the caller is enough.
noexcept and exceptions
noexcept promises no exceptions — vector reallocation and move operations rely on it. If it throws anyway, std::terminate ends the program; don't mark it when in doubt.
optional for failure
For "expected may fail" operations, returning std::optional is lighter than throwing — callers explicitly handle the empty case. Reserve exceptions for truly unexpected errors.
std::expected
std::expected (C++23) carries either a value or an error description — richer than optional, more predictable than exceptions. A natural fit for parsing and validation code.
Exception safety
Exception safety comes from RAII: cleanup belongs in local destructors so it runs on every exit path — normal return, exception, anything — preventing leaks and inconsistent state.
errno with C
errno is a C-era global error code, overwritten by the next failed call and not thread-safe. In C++ prefer exceptions; read errno immediately when interacting with C functions.
12.File and Stream I/O
Reading and writing files, line-by-line reading, formatted output, filesystem paths, and binary files.
Write file
ofstream opens a file for writing; << writes formatted output. The destructor closes it; an explicit close() surfaces write failures earlier. Default is to overwrite existing files.
Read file
ifstream opens a file for reading; getline reads line by line. The loop condition is the return value of getline — it stops at EOF or on failure.
Line vs word
getline reads an entire line; >> reads a single token and skips whitespace. Mixing them: after >> you must ignore() the leftover newline or the next getline returns an empty string.
Format control
<iomanip>'s setw / setprecision / fixed control output formatting — column alignment and decimal precision when printing tables.
In-memory stream to disk
ostringstream assembles the output in memory first, then a single write hits the disk — fewer I/O syscalls. For input, parse through istringstream first to validate.
filesystem directories
<filesystem> (C++17) handles paths and directories: exists / create_directories / iteration. More robust than string-concatenated paths, with automatic separator handling.
Path components
fs::path handles decomposition and joining with the platform-correct separator. filename / extension / parent_path extract the parts.
Binary file
Binary mode std::ios::binary skips newline translation; write/read operate on raw byte blocks. When dumping structs, mind alignment and endianness for portability.
Validate stdin
When cin >> fails, the stream enters the fail state and every subsequent read fails. Call clear() to reset state and ignore() to drop the bad input before continuing. Always validate cin after reading.
13.Common Pitfalls
Ten classic C++ anti-patterns (BAD) with the correct alternative (GOOD) — color-coded for side-by-side comparison.
Signed/unsigned mix
Comparing signed with unsigned implicitly converts the signed operand to unsigned, turning -1 into a huge positive value. Cast explicitly or unify signedness before comparing.
Dangling references
Returning a reference or pointer to a local is a dangling reference: the memory is gone after the function returns, and any use is undefined behavior. Return by value or extend the object's lifetime.
Non-virtual base destructor
Deleting a derived object through a base pointer requires a virtual base destructor — otherwise the derived subobject isn't destroyed, leaking its resources.
Integer division
Dividing two ints yields an int (truncation) — assigning to a double afterwards doesn't recover the fraction. Cast at least one operand to a floating type before dividing.
String concat in loop
s = s + x copies the entire string each iteration into a fresh temporary — O(n²). reserve + += appends in place — O(n). For large inputs the difference is dramatic.
using namespace std
using namespace std in a header leaks every std symbol into everyone who includes it — guaranteed name clashes. Use precise using-declarations or qualify with std::.
i++ vs ++i
i++ returns the old value (a copy/temporary), ++i increments directly. For int it doesn't matter; for user-defined types and iterators, ++i avoids the extra copy.
const correctness
Read-only parameters should be const& — self-documenting and copy-free. const correctness lets the compiler catch unintended writes and signals to callers that the argument isn't modified.
Macros vs functions
Macros bypass type checking, ignore scope, and can re-evaluate their arguments. Prefer const/constexpr functions or templates whenever you can.
Copy in range-for
Range-for by value copies every element. For large objects, use const auto& for read-only access or auto& for mutation. By-value is only right when items are small and a copy is desired.
14.Threads and Concurrency
std::thread, mutexes, atomics, condition variables, and async tasks.
Create a thread
std::thread spawns a new thread to run a callable (function or lambda). The thread object must be joined or detached before destruction or std::terminate fires.
join and detach
join blocks the current thread until the child finishes; detach lets the child run independently — after detaching you can't join, and any objects it accesses must outlive it.
mutex
mutex protects shared data by allowing only one holder at a time. Manual lock/unlock is easy to forget on exception paths — prefer lock_guard or unique_lock.
lock_guard
lock_guard manages a mutex via RAII: locks on construction, unlocks on destruction. Every exit path — including exceptions — releases the lock. The standard way to lock.
atomics
std::atomic offers lock-free atomic operations on fundamental types. fetch_add / load / store are all atomic and far cheaper than a mutex for simple counters.
condition_variable
condition_variable lets threads wait on a condition: wait releases the lock and blocks; notify wakes it. Always pass a predicate to wait to guard against spurious wake-ups.
async / future
std::async launches an async task and returns a future; get() blocks for the result. Simpler than hand-rolling thread + shared state; pass std::launch::async to force a new thread.
thread_local
thread_local gives each thread its own independent copy — a natural fit for lock-free caches, counters, or scratch state. Destroyed when the thread exits.
Data races
Two threads reading and writing the same non-atomic variable is a data race — undefined behavior with unpredictable results. Synchronize with atomic or mutex.
Parallel algorithms
C++17 <execution> adds execution policies to algorithms: par for parallelism, unseq for vectorization. On large datasets it uses all cores — provided elements share no mutable state.
15.Networking (Sockets)
POSIX socket creation, listen, connect, send/recv, and timeouts (for cross-platform networking prefer Boost.Asio or libcurl).
Create a socket
POSIX sockets are the bedrock of network I/O: socket() creates one — AF_INET for IPv4, SOCK_STREAM for TCP. The return is a file descriptor; -1 indicates failure.
bind and listen
bind attaches the socket to a port; listen starts accepting connections. htons converts host-byte-order to network-byte-order. sockaddr_in holds an IPv4 address.
accept
accept pulls the next client connection off the queue and returns a new socket — one fd per connection. The original listening fd keeps accepting further connections.
Client connect
On the client, socket() + connect() reach the server. inet_pton converts a dotted-decimal IP to binary. connect returns -1 on failure.
send and recv
send/recv exchange bytes over a TCP socket. recv returns 0 when the peer closes, -1 on error. TCP is a byte stream — frame the messages yourself.
Hostname resolution
getaddrinfo resolves a hostname + service into a list of addresses you can connect to — handling IPv4/IPv6 for you. The recommended replacement for hand-written inet_pton + port.
Timeouts
SO_RCVTIMEO sets a recv timeout — on expiry recv returns -1 with errno=EWOULDBLOCK. A blocking recv becomes controllable and won't hang forever.
Minimal HTTP request
HTTP requests are a text protocol: request line + headers + blank line. The demo sends raw socket bytes; production code should use libcurl (handles redirects, TLS, compression).
16.Time and Date
chrono duration and time_point, the two clocks, formatting, sleeping, and elapsed-time measurement.
duration
duration represents a length of time with a typed unit — seconds / milliseconds / microseconds. Literal suffixes s / ms / us are intuitive; duration_cast converts across units.
time_point
time_point is a moment on the timeline — a clock plus a duration offset. Add/subtract durations to move along the line; subtract two time_points to get a duration.
system_clock
system_clock is the wall clock; it interchanges with time_t via to_time_t / from_time_t. Use it for calendar times and log timestamps. Affected by system clock changes.
steady_clock
steady_clock is monotonic and immune to system clock changes — the right choice for timing (elapsed measurements, deadlines). Use system_clock only for human-readable times.
Format time
put_time formats a time_t into a local string using a strftime pattern. %Y-%m-%d %H:%M:%S is the most common. localtime returns a pointer into a static buffer — not thread-safe.
Thread sleep
sleep_for sleeps for a duration; sleep_until sleeps until a time_point. They block the current thread — sleeping the main thread freezes the UI, so use them only for background/test code.
Measure elapsed
The timing idiom: record a start, subtract from end to get a duration, duration_cast to the desired unit, then count() for the value. Use steady_clock to ignore system clock changes.
C-style time conversion
time_t is a seconds-since-epoch timestamp; gmtime converts to UTC, localtime to local time, strftime formats the result. These functions share static buffers — not thread-safe.
Time zones
C++20's zoned_time renders a time with a time zone, handling daylight savings automatically. The pre-C++20 standard library has no time-zone support — fall back to localtime or a third-party library.
17.Processes and Signals
system, fork/exec/wait for child processes, environment variables, signal handling, and piped output (POSIX concepts).
system
system() asks the shell to execute a string command — easy but unsafe (command injection, shell quirks). When you need to capture output or pass arguments, use fork + exec or popen.
fork
fork duplicates the current process. It returns twice: the parent gets the child's pid, the child gets 0; -1 means failure. After fork both resume at the fork call.
exec
The exec family loads a new program into the current process, replacing it. Pair fork + exec to launch an external command. On success exec doesn't return; on failure it returns -1 — the child must handle that path.
wait
waitpid waits for a specific child to exit and returns its status. WIFEXITED checks for normal exit; WEXITSTATUS extracts the code. A child you don't wait on becomes a zombie.
Environment variables
getenv reads an env var (nullptr if absent), setenv writes it, unsetenv removes it. Environment variables are the simple config channel from parent to child processes.
signal
signal registers a handler for signals like SIGINT (Ctrl+C) and SIGTERM (the default for kill). Inside a handler do only async-signal-safe operations — no allocation, no I/O.
sigaction
sigaction is more reliable than signal: it supports a signal mask and flags. SA_RESTART automatically resumes blocking calls interrupted by a signal. Prefer sigaction in production.
exit vs _exit
exit terminates the process, runs atexit handlers, and flushes buffers. _exit terminates immediately with no cleanup. A forked child should _exit to avoid double-cleanup of the parent's resources.
popen
popen runs a command and pipes to its output ("r" to read, "w" to write input) — unlike system, it can capture output. pclose closes the pipe and waits, returning the exit status.
18.Regular Expressions
std::regex matching, search, replace, capture groups, flags, and raw string literals.
Basic match
std::regex defaults to the ECMAScript grammar. regex_match requires the whole string to match; regex_search finds a substring. R"()" raw strings keep regexes readable.
Full match and groups
regex_search finds the first matching substring; smatch holds the full match (m[0]) and the capture groups (m[1]…). regex_match requires a full-string match — ideal for format validation.
Iterate all matches
Loop regex_search starting after the previous match to walk all of them. m.suffix().first gives the starting point past the match — or use a regex_iterator directly.
Replace
regex_replace globally rewrites every match. In the replacement template $& is the whole match and $1 is the first capture group. For position-aware edits use a regex_iterator.
sregex_iterator
sregex_iterator packages "find every match" into a real iterator — much cleaner than a hand-written while regex_search loop when you want to extract them all.
Capture groups
Parentheses define capture groups; smatch indexes them by number. (?:...) is a non-capturing group — groups without numbering. Named groups (?<name>...) are accessed via m["name"].
Match flags
The second argument of std::regex sets flags: icase for case-insensitive, multiline so ^/$ match line starts/ends, ECMAScript/extended to pick a grammar dialect. Combine with |.
Raw string regex
Inside R"(...)" the backslash is literal — write regexes and paths without escape-counting. If the body contains )" use a custom delimiter: R"tag(...)tag". Always prefer raw string literals for regex.
regex_error
An invalid regex throws std::regex_error at construction — catch it so a bad pattern doesn't crash you. For expensive patterns reuse the regex object to skip recompilation.
19.Build and Debug
Compiler flags, Makefile/CMake, formatters, sanitizers, debuggers, and profilers.
Common flags
Common flags: -std for the standard, -O for optimization, -g for debug info, -Wall -Wextra for warnings, -Werror to make warnings fatal. Multi-file: -c each source then link the objects.
Makefile
A Makefile declares targets and dependencies; make rebuilds only what's stale. $< is the first prerequisite, $@ is the target, $^ is all prerequisites. Recipe lines must start with a tab.
CMake
CMake is a declarative build generator — it produces Makefiles, VS projects, etc. target_link_libraries links libraries, find_package locates dependencies. Build in a separate build/ directory.
pkg-config
pkg-config queries a library's compile/link flags; $(pkg-config ...) injects them via shell substitution — the standard way to avoid hand-typed include paths and -l flags.
clang-format
clang-format auto-formats code; commit a .clang-format file to lock the style. ColumnLimit sets the line width, SortIncludes orders headers. Run it before committing to stay consistent.
Sanitizers
Compile-time sanitizers catch runtime memory and concurrency bugs: address for out-of-bounds/leaks, undefined for UB, thread for data races. Always-on for tests.
gdb
gdb is the command-line debugger; compile with -g to embed symbols. break sets a breakpoint, run launches, bt shows the stack, print inspects a value. VSCode/CLion debuggers are GUIs over gdb.
valgrind
valgrind finds runtime memory issues: uninitialized reads, out-of-bounds, leaks, double-frees. --leak-check=full prints a stack trace for every leak. It's slow — run it on a subset of tests.
Static library
ar packs multiple .o files into a static library lib*.a; -L points to a library directory and -l names the library (strip the lib prefix and .a suffix). Static archives get linked into the binary — no runtime dependency.
Profiling
gprof/perf profile hot functions. Build with g++ -pg to instrument, run the binary, then gprof reports call counts and time per function — that's where to optimize.
Official Links
Direct links to the official docs and resources.
About this Cheatsheet
This page is a self-contained C++17/C++20 cheatsheet covering the core language, the Standard Template Library (STL) and the build toolchain — roughly 80% of what you actually use in real projects. The emphasis is on modern idioms: smart pointers (unique_ptr / shared_ptr), move semantics, auto type deduction, range-based for, structured bindings, and C++20 concepts and ranges. C++ was created by Bjarne Stroustrup in 1985 and combines C's raw performance with high-level abstraction, which makes it a cornerstone language for systems programming, game engines and high-performance computing. Its 19 chapters each focus on a single topic: basic syntax, variables, types and pointers, control flow, functions, strings, collections, memory management, object-oriented programming, error handling, input and output, common pitfalls, concurrency, networking, time, processes, regular expressions and build tools. Every subsection pairs a short concept introduction with a copy-and-paste-ready code snippet, so it is easy to look things up and experiment. All code and text is rendered locally in your browser; no data ever leaves your device. For authoritative references, see cppreference and the ISO C++ standard drafts.
Version 2.1.0