C++ Cheatsheet
C++ is a general-purpose programming language created by Bjarne Stroustrup in 1979, first released in 1985. It supports procedural, object-oriented, and generic programming. C++ compiles to native machine code, giving direct control over hardware and memory — which makes it the standard choice for systems software, game engines, embedded systems, and high-performance applications. This cheatsheet is a comprehensive reference for building real applications in C++.
Getting Started
Section titled “Getting Started”What is a Compiler?
Section titled “What is a Compiler?”C++ is a compiled language — you write source code in .cpp files, then a compiler translates it into a native executable that your OS can run directly. There is no interpreter or runtime like Python or JavaScript.
source.cpp → [Compiler] → program (executable)Compilers
Section titled “Compilers”| Compiler | Command | Platforms | Notes |
|---|---|---|---|
| GCC (g++) | g++ | Linux, macOS, Windows (MinGW) | Most common on Linux. Free, open-source. |
| Clang (clang++) | clang++ | macOS, Linux, Windows | Default on macOS (via Xcode). Better error messages. |
| MSVC | cl | Windows | Comes with Visual Studio. Default on Windows. |
All three support C++17 and C++20. For this cheatsheet, examples use g++ — replace with clang++ if you prefer, the flags are the same.
Installing a Compiler
Section titled “Installing a Compiler”macOS — Clang is included with Xcode Command Line Tools:
xcode-select --install# Verify:clang++ --versionUbuntu / Debian:
sudo apt updatesudo apt install g++# Verify:g++ --versionFedora / RHEL:
sudo dnf install gcc-c++Windows — install one of:
- Visual Studio (includes MSVC) — full IDE
- MSYS2 (includes GCC/MinGW) — Unix-like terminal
- WSL — run Ubuntu inside Windows, then
apt install g++
Compiling and Running Your First Program
Section titled “Compiling and Running Your First Program”Create a file called hello.cpp:
#include <iostream>
int main() { std::cout << "Hello, World!" << std::endl; return 0;}Compile and run:
g++ hello.cpp -o hello # compile./hello # run# Output: Hello, World!Compiler Flags
Section titled “Compiler Flags”| Flag | Purpose | Example |
|---|---|---|
-o name | Name the output executable | g++ main.cpp -o app |
-std=c++17 | Use C++17 standard | g++ -std=c++17 main.cpp -o app |
-Wall | Enable all common warnings | Catches potential bugs |
-Wextra | Enable extra warnings | Even more thorough |
-Werror | Treat warnings as errors | Forces you to fix all warnings |
-g | Include debug info | Required for gdb / lldb debugging |
-O2 | Optimization level 2 | Faster executable, slower compile |
-I path | Add include directory | g++ -I include main.cpp |
-l lib | Link a library | g++ main.cpp -lpthread |
-c | Compile only (produce .o, don’t link) | g++ -c main.cpp -o main.o |
A typical development command:
g++ -std=c++17 -Wall -Wextra -Werror -g main.cpp -o appA typical release build:
g++ -std=c++17 -O2 main.cpp -o appC++ Standards
Section titled “C++ Standards”| Standard | Year | Key Features |
|---|---|---|
| C++98 | 1998 | Original standard, STL, templates |
| C++11 | 2011 | auto, lambdas, smart pointers, move semantics, nullptr, range-for |
| C++14 | 2014 | Generic lambdas, make_unique, relaxed constexpr |
| C++17 | 2017 | Structured bindings, optional, variant, string_view, if constexpr |
| C++20 | 2020 | Concepts, ranges, coroutines, std::format, modules |
| C++23 | 2023 | std::expected, std::print, std::flat_map |
Use -std=c++17 as a default — it has the best balance of modern features and compiler support. Most code in this cheatsheet uses C++17 or earlier.
RFC 959, Section Getting Started — "cppreference.com"
Program Structure
Section titled “Program Structure”Every C++ program follows a standard structure: include header files, declare the namespace, and define the main() function as the entry point. The #include directive imports library headers, using namespace std; brings the standard library into scope, and main() is where execution begins.
#include <iostream>using namespace std;
int main(){ cout << "Hello, World!" << endl; int num; cout << "Enter a number: "; cin >> num; cout << "You entered: " << num << endl; return 0;}The return 0; statement signals successful program termination to the operating system.
RFC 959, Section Basic Structure of C++ Program
Comments
Section titled “Comments”Comments are non-executable annotations in source code. C++ supports two forms:
- Single-line comments start with
//and extend to the end of the line. - Multi-line comments are enclosed between
/*and*/and can span multiple lines.
// This is a single-line comment
/* This is a multi-line comment */RFC 959, Section Comments
Project Structure and Compilation
Section titled “Project Structure and Compilation”Real C++ projects separate declarations from implementations using header files (.h or .hpp) and source files (.cpp). Headers contain class declarations, function prototypes, and constants. Source files contain the implementations.
Header and Source Files
Section titled “Header and Source Files”// math_utils.h — declaration#ifndef MATH_UTILS_H#define MATH_UTILS_H
double circleArea(double radius);
class Calculator { double result;public: Calculator(); void add(double val); void subtract(double val); double getResult() const;};
#endif// math_utils.cpp — implementation#include "math_utils.h"#include <cmath>
double circleArea(double radius) { return M_PI * radius * radius;}
Calculator::Calculator() : result(0) {}void Calculator::add(double val) { result += val; }void Calculator::subtract(double val) { result -= val; }double Calculator::getResult() const { return result; }// main.cpp — entry point#include <iostream>#include "math_utils.h"
int main() { Calculator calc; calc.add(10); calc.subtract(3); std::cout << calc.getResult() << std::endl; // 7 return 0;}Typical Project Layout
Section titled “Typical Project Layout”my_project/├── CMakeLists.txt # Build configuration├── include/ # Public headers│ └── my_project/│ └── math_utils.h├── src/ # Source files│ ├── main.cpp│ └── math_utils.cpp├── tests/ # Test files│ └── test_math.cpp├── lib/ # Third-party libraries└── build/ # Build output (gitignored)Building with CMake
Section titled “Building with CMake”CMake is the standard build system for C++ projects.
cmake_minimum_required(VERSION 3.16)project(MyProject LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(app src/main.cpp src/math_utils.cpp)
target_include_directories(app PRIVATE include)Build commands:
mkdir build && cd buildcmake ..cmake --build ../appBuilding with Make
Section titled “Building with Make”A Makefile automates compilation without requiring CMake. This Makefile works with the project layout above — it discovers all .cpp files in src/, compiles them to obj/, and links them into an executable.
NAME = my_appSRC_DIR = srcOBJ_DIR = objINCLUDE_DIR = includeSRC = $(wildcard $(SRC_DIR)/*.cpp)OBJ = $(SRC:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
CC = g++C_FLAGS = -Wall -Wextra -WerrorL_FLAGS =
all: $(NAME)
# Link$(NAME): $(OBJ) $(CC) $(L_FLAGS) $(OBJ) -o $@
$(OBJ_DIR): mkdir -p $(OBJ_DIR)
# Compile$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR) $(CC) $(C_FLAGS) -c $< -I $(INCLUDE_DIR) -o $@
clean: rm -rf $(OBJ_DIR)
fclean: clean rm -f $(NAME)
re: fclean allBuild commands:
make # buildmake clean # remove object filesmake fclean # remove object files + executablemake re # full rebuild./my_app # run| Variable | Purpose |
|---|---|
NAME | Executable name |
SRC_DIR / OBJ_DIR / INCLUDE_DIR | Directory paths |
SRC | All .cpp files discovered via wildcard |
OBJ | Corresponding .o files via pattern substitution |
CC | Compiler (g++, clang++) |
C_FLAGS | Compiler flags (warnings, standard) |
L_FLAGS | Linker flags (e.g. -lm, -lpthread) |
| Target | Effect |
|---|---|
all | Build the executable (default) |
clean | Remove object files |
fclean | Remove object files and executable |
re | Full clean rebuild |
Compilation Process
Section titled “Compilation Process”C++ compilation happens in four stages:
| Stage | What happens | Tool |
|---|---|---|
| Preprocessing | Expands #include, #define, macros | Preprocessor |
| Compilation | Translates .cpp to assembly | Compiler |
| Assembly | Converts assembly to object files (.o) | Assembler |
| Linking | Combines object files into executable | Linker |
# Compile and link manuallyg++ -std=c++17 -c src/main.cpp -o build/main.og++ -std=c++17 -c src/math_utils.cpp -o build/math_utils.og++ build/main.o build/math_utils.o -o build/appRFC 959, Section Project Structure — "cppreference.com"
Variables and Data Types
Section titled “Variables and Data Types”A variable is a named storage location in memory. Variables must be declared with a type before use. Variable names can contain letters, digits, and underscores, and must begin with a letter or underscore. Identifiers are unique names for variables. Constants are values that do not change during program execution.
int age = 20;double height = 5.7;char grade = 'A';string name = "John";RFC 959, Section Variables
Data Types
Section titled “Data Types”C++ provides six fundamental data types for storing different kinds of values.
RFC 959, Section Data Types
| Type | Size | Description | Example |
|---|---|---|---|
int | 4 bytes | Whole numbers | 10, -5, 0 |
float | 4 bytes | Decimal numbers, single precision | 3.14f |
double | 8 bytes | Decimal numbers, double precision | 3.14159 |
char | 1 byte | Single characters | 'A', 'b' |
bool | 1 byte | Boolean values | true, false |
string | Variable | Text sequences | "Hello" |
RFC 959, Section Data Types
Each type has a specific use case:
int age = 25;float pi = 3.14f;float area = pi * 5 * 5;
double price = 99.99;double discount = price * 0.1;
char grade = 'A';
bool isStudent = true;
string firstName = "John";string lastName = "Doe";string fullName = firstName + " " + lastName;RFC 959, Section Data Types
Input and Output
Section titled “Input and Output”C++ uses the <iostream> library for console I/O. The cout object with the insertion operator << writes output to the console. The cin object with the extraction operator >> reads input from the user.
#include <iostream>using namespace std;
int main(){ int age; cout << "Enter your age: "; cin >> age; cout << "Your age is: " << age << endl; return 0;}The << operator can be chained to output multiple values in a single statement. The endl manipulator inserts a newline and flushes the output buffer.
RFC 959, Section Input and Output
Conditional Statements
Section titled “Conditional Statements”Conditional statements control the flow of execution based on boolean conditions. C++ provides five forms.
if Statement
Section titled “if Statement”Executes a block of code only when the condition evaluates to true.
int i = 10;
if (i < 15) { cout << "10 is less than 15";}if-else Statement
Section titled “if-else Statement”Provides two execution paths — one for true, one for false.
int i = 10;
if (i < 15) { cout << "10 is less than 15";} else { cout << "10 is not less than 15";}else if Ladder
Section titled “else if Ladder”Tests multiple conditions sequentially. The first condition that evaluates to true executes its block; the rest are skipped.
int marks = 85;
if (marks >= 90) { cout << "A" << endl;} else if (marks >= 80) { cout << "B" << endl;} else if (marks >= 70) { cout << "C" << endl;} else if (marks >= 60) { cout << "D" << endl;} else { cout << "F" << endl;}switch Statement
Section titled “switch Statement”Evaluates a variable against multiple case values. Each case requires a break to prevent fall-through. The default case handles unmatched values.
char x = 'A';
switch (x) { case 'A': cout << "A"; break; case 'B': cout << "B"; break; default: cout << "Other than A and B"; break;}Ternary Operator
Section titled “Ternary Operator”A compact conditional expression: condition ? value_if_true : value_if_false.
int x = 10, y = 20;
int max_val = (x > y) ? x : y;cout << "The maximum value is " << max_val;RFC 959, Section Conditional Statements
Loops execute a block of code repeatedly. C++ provides three loop constructs.
for Loop
Section titled “for Loop”Repeats a fixed number of times. The loop header declares the initializer, condition, and increment in a single line.
for (int i = 5; i < 10; i++) { cout << "Hi" << endl;}while Loop
Section titled “while Loop”Repeats while a condition is true. The condition is checked before each iteration — if it is false initially, the body never executes.
int i = 0;while (i < 5) { cout << "Hi" << endl; i++;}do-while Loop
Section titled “do-while Loop”Executes the body at least once, then checks the condition. The condition is evaluated after each iteration.
int i = 0;do { cout << "Hi" << endl; i++;} while (i < 5);RFC 959, Section Loops
Arrays
Section titled “Arrays”An array is a fixed-size collection of elements of the same type, stored in contiguous memory. Elements are accessed by zero-based index.
int arr[5] = {2, 4, 8, 12, 16};
// Access elementscout << arr[0] << endl; // 2cout << arr[2] << endl; // 8
// Modify an elementarr[1] = 10;
// Iterate over arrayfor (int i = 0; i < 5; i++) { cout << arr[i] << " ";}RFC 959, Section Arrays
Multi-Dimensional Arrays
Section titled “Multi-Dimensional Arrays”A multi-dimensional array is an array of arrays. The most common form is a two-dimensional array organized as rows and columns.
int matrix[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
// Access element at row 1, column 2cout << matrix[1][2] << endl; // 7
// Iterate over 2D arrayfor (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { cout << matrix[i][j] << " "; } cout << endl;}RFC 959, Section Multi-Dimensional Arrays
Vectors
Section titled “Vectors”A vector is a dynamic array from the C++ Standard Template Library (STL). Unlike fixed-size arrays, vectors can grow and shrink at runtime. Include <vector> to use them.
#include <vector>using namespace std;
// Empty vectorvector<int> v1;
// Vector of size 3, all elements initialized to 5vector<int> v2(3, 5);
// Vector with initializer listvector<int> v3 = {1, 2, 3};Key vector operations:
vector<int> v = {1, 2, 3};
v.push_back(4); // Add element to end: {1, 2, 3, 4}v.pop_back(); // Remove last element: {1, 2, 3}cout << v.size(); // Number of elements: 3v.clear(); // Remove all elements| Method | Description |
|---|---|
push_back(val) | Adds an element to the end |
pop_back() | Removes the last element |
size() | Returns the number of elements |
clear() | Removes all elements |
RFC 959, Section Vectors
References and Pointers
Section titled “References and Pointers”References
Section titled “References”A reference is an alias for an existing variable. It shares the same memory address as the original and cannot be reassigned after initialization.
int x = 10;int &ref = x; // ref is an alias for x
ref = 22; // modifies xcout << x << endl; // 22| Rule | Example |
|---|---|
| Must be initialized at declaration | int& r = x; (not int& r;) |
| Cannot be reassigned | After int& r = x;, r = y; changes x’s value, not the binding |
| Cannot be null | References always refer to a valid object |
RFC 959, Section References
Pointers
Section titled “Pointers”A pointer is a variable that stores the memory address of another variable. The address-of operator & retrieves a variable’s address. The dereference operator * accesses the value at the address.
int var = 10;int *ptr = &var; // ptr holds the address of var
cout << var; // 10 (value)cout << &var; // 0x7ffc... (address)cout << ptr; // 0x7ffc... (same address)cout << *ptr; // 10 (dereference — value at address)
*ptr = 20; // modifies var through the pointercout << var; // 20nullptr
Section titled “nullptr”nullptr (C++11) is a type-safe null pointer constant. Always use it instead of NULL or 0.
int* ptr = nullptr;
if (ptr == nullptr) { cout << "Pointer is null" << endl;}
// Shorthand — nullptr evaluates to falseif (!ptr) { cout << "Pointer is null" << endl;}Pointer Arithmetic
Section titled “Pointer Arithmetic”Pointers support arithmetic that moves by the size of the pointed-to type.
int arr[5] = {10, 20, 30, 40, 50};int* p = arr; // points to arr[0]
cout << *p; // 10cout << *(p + 1); // 20 (next int, 4 bytes forward)cout << *(p + 3); // 40p++; // now points to arr[1]cout << *p; // 20
// Distance between pointersint* start = &arr[0];int* end = &arr[4];cout << (end - start); // 4 (elements, not bytes)Pointers and Arrays
Section titled “Pointers and Arrays”An array name decays to a pointer to its first element. This is why arrays and pointers are often interchangeable.
int arr[3] = {10, 20, 30};int* p = arr; // arr decays to &arr[0]
// These are equivalent:cout << arr[1]; // 20cout << *(arr + 1); // 20cout << p[1]; // 20cout << *(p + 1); // 20const Pointers
Section titled “const Pointers”| Declaration | Can change value? | Can change pointer? |
|---|---|---|
int* p | Yes | Yes |
const int* p | No | Yes |
int* const p | Yes | No |
const int* const p | No | No |
int x = 10, y = 20;
const int* ptr1 = &x; // pointer to const int// *ptr1 = 30; // ERROR: cannot change valueptr1 = &y; // OK: can change where it points
int* const ptr2 = &x; // const pointer to int*ptr2 = 30; // OK: can change value// ptr2 = &y; // ERROR: cannot change pointerRead it right-to-left: const int* p — “p is a pointer to int that is const”. int* const p — “p is a const pointer to int”.
Pointers to Objects
Section titled “Pointers to Objects”Use the arrow operator -> to access members through a pointer.
struct Point { int x, y; };
Point p = {3, 4};Point* ptr = &p;
cout << ptr->x; // 3 (same as (*ptr).x)cout << ptr->y; // 4ptr->x = 10; // modify through pointerFunction Pointers
Section titled “Function Pointers”A function pointer stores the address of a function. Useful for callbacks and strategy patterns.
int add(int a, int b) { return a + b; }int mul(int a, int b) { return a * b; }
// Declare function pointerint (*op)(int, int) = add;cout << op(3, 4); // 7
op = mul;cout << op(3, 4); // 12
// As function parametervoid apply(int a, int b, int (*fn)(int, int)) { cout << fn(a, b) << endl;}apply(5, 3, add); // 8apply(5, 3, mul); // 15Pointers vs References — When to Use Which
Section titled “Pointers vs References — When to Use Which”| Pointer | Reference | |
|---|---|---|
| Can be null | Yes | No |
| Can be reassigned | Yes | No |
| Can do arithmetic | Yes | No |
| Syntax | *ptr, ptr->member | Direct use, like the original |
| Use for | Optional values, dynamic memory, arrays, polymorphism | Function parameters, aliases, operator overloading |
RFC 959, Section Pointers — "cppreference.com"
Functions
Section titled “Functions”A function is a reusable block of code that performs a specific task. Functions can accept parameters and return values. The general syntax is:
returnType functionName(parameters) { // function body return value;}Example:
void greet() { cout << "Hello, World!" << endl;}
int main() { greet(); return 0;}Functions help avoid repeating code and make programs more organized. They can take inputs (parameters) and return values, both of which are optional.
RFC 959, Section Functions
Function Features
Section titled “Function Features”Default Parameters
Section titled “Default Parameters”void log(const string& msg, int level = 1) { if (level > 0) cout << "[" << level << "] " << msg << endl;}
log("hello"); // level defaults to 1log("error", 3); // level = 3Pass by Value, Reference, and Pointer
Section titled “Pass by Value, Reference, and Pointer”void byValue(int x) { x = 0; } // copy — original unchangedvoid byRef(int& x) { x = 0; } // reference — modifies originalvoid byPtr(int* x) { *x = 0; } // pointer — modifies originalvoid byConstRef(const string& s) { ... } // read-only, no copyOverloaded Functions
Section titled “Overloaded Functions”int area(int side) { return side * side; }int area(int width, int height) { return width * height; }double area(double radius) { return 3.14159 * radius * radius; }Inline Functions
Section titled “Inline Functions”The inline keyword suggests the compiler replace the function call with its body. Modern compilers typically decide this automatically.
inline int square(int x) { return x * x; }Recursive Functions
Section titled “Recursive Functions”int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);}RFC 959, Section Functions — "cppreference.com"
String Functions
Section titled “String Functions”The string class provides built-in methods for common text operations.
| Function | Description | Example |
|---|---|---|
length() | Returns the number of characters | s.length() |
substr(pos, len) | Extracts a substring starting at pos with length len | s.substr(0, 5) |
append(str) | Appends str to the end of the string | s.append(" world") |
compare(str) | Lexicographic comparison; returns 0 if equal | s.compare("hello") |
empty() | Returns true if the string has no characters | s.empty() |
string s = "Hello, World!";
cout << s.length() << endl; // 13cout << s.substr(0, 5) << endl; // Hellos.append(" C++"); // "Hello, World! C++"cout << s.compare("Hello") << endl; // non-zero (not equal)cout << s.empty() << endl; // 0 (false)RFC 959, Section String Functions
Math Functions
Section titled “Math Functions”C++ provides standard mathematical functions for common operations.
| Function | Description | Example |
|---|---|---|
min(x, y) | Returns the smaller of two values | min(5, 3) returns 3 |
max(x, y) | Returns the larger of two values | max(5, 3) returns 5 |
sqrt(x) | Returns the square root | sqrt(16) returns 4 |
ceil(x) | Rounds up to the nearest integer | ceil(4.3) returns 5 |
floor(x) | Rounds down to the nearest integer | floor(4.7) returns 4 |
pow(x, n) | Returns x raised to the power n | pow(2, 3) returns 8 |
#include <cmath>
cout << min(5, 3) << endl; // 3cout << max(5, 3) << endl; // 5cout << sqrt(16) << endl; // 4cout << ceil(4.3) << endl; // 5cout << floor(4.7) << endl; // 4cout << pow(2, 3) << endl; // 8RFC 959, Section Math Functions
Operators
Section titled “Operators”C++ provides a comprehensive set of operators for performing computations, comparisons, and logical operations.
Arithmetic Operators
Section titled “Arithmetic Operators”| Operator | Description | Example |
|---|---|---|
+ | Addition | a + b |
- | Subtraction | a - b |
* | Multiplication | a * b |
/ | Division | a / b |
% | Modulus (remainder) | a % b |
++ | Increment | a++ or ++a |
-- | Decrement | a-- or --a |
Relational Operators
Section titled “Relational Operators”| Operator | Description | Example |
|---|---|---|
== | Equal to | a == b |
!= | Not equal to | a != b |
> | Greater than | a > b |
< | Less than | a < b |
>= | Greater than or equal to | a >= b |
<= | Less than or equal to | a <= b |
Logical Operators
Section titled “Logical Operators”| Operator | Description | Example |
|---|---|---|
&& | Logical AND | a && b |
|| | Logical OR | a || b |
! | Logical NOT | !a |
Bitwise Operators
Section titled “Bitwise Operators”| Operator | Description | Example |
|---|---|---|
& | Bitwise AND | a & b |
| | Bitwise OR | a | b |
^ | Bitwise XOR | a ^ b |
~ | Bitwise NOT | ~a |
<< | Left shift | a << 2 |
>> | Right shift | a >> 2 |
Assignment Operators
Section titled “Assignment Operators”| Operator | Description | Example |
|---|---|---|
= | Assign | a = 5 |
+= | Add and assign | a += 3 |
-= | Subtract and assign | a -= 3 |
*= | Multiply and assign | a *= 3 |
/= | Divide and assign | a /= 3 |
%= | Modulus and assign | a %= 3 |
RFC 959, Section Operators — "cppreference.com"
const and constexpr
Section titled “const and constexpr”The const qualifier makes a variable or parameter read-only after initialization. Use it liberally — it prevents bugs and documents intent.
const int MAX = 100;// MAX = 200; // ERROR: cannot modify
const string& name = getName(); // read-only reference, no copy
class Circle { double radius;public: double area() const { return 3.14 * radius * radius; } // does not modify object};constexpr
Section titled “constexpr”constexpr (C++11) marks values and functions that can be evaluated at compile time.
constexpr int square(int x) { return x * x; }constexpr int val = square(5); // computed at compile time: 25
constexpr int fib(int n) { return (n <= 1) ? n : fib(n - 1) + fib(n - 2);}static_assert(fib(10) == 55); // verified at compile timeconst Correctness Cheatsheet
Section titled “const Correctness Cheatsheet”| Declaration | Meaning |
|---|---|
const int x = 5 | x cannot be changed |
const int* p | Cannot change value through p (pointer to const) |
int* const p | Cannot reassign p itself (const pointer) |
const int* const p | Both are const |
void f(const T& x) | Function does not modify x |
int get() const | Member function does not modify the object |
RFC 959, Section const and constexpr — "cppreference.com"
Classes and Objects
Section titled “Classes and Objects”A class is a user-defined data type that bundles data members (variables) and member functions (methods) into a single unit. An object is an instance of a class.
class Car {public: string brand; int year;
void display() { cout << brand << " (" << year << ")" << endl; }};
int main() { Car c; c.brand = "Toyota"; c.year = 2024; c.display(); // Toyota (2024)}RFC 959, Section Object-Oriented Programming
Access Specifiers
Section titled “Access Specifiers”Access specifiers control the visibility of class members.
| Specifier | Access within class | Access in derived class | Access outside class |
|---|---|---|---|
public | Yes | Yes | Yes |
protected | Yes | Yes | No |
private | Yes | No | No |
class Account {private: double balance; // only accessible within this classprotected: string accountId; // accessible in derived classespublic: string ownerName; // accessible everywhere
void setBalance(double b) { balance = b; } double getBalance() { return balance; }};RFC 959, Section Object-Oriented Programming — "cppreference.com"
Constructors and Destructors
Section titled “Constructors and Destructors”A constructor initializes an object when it is created. A destructor cleans up when an object goes out of scope.
class Point { int x, y;public: Point() : x(0), y(0) {} // default constructor Point(int x, int y) : x(x), y(y) {} // parameterized constructor Point(const Point& p) : x(p.x), y(p.y) {} // copy constructor ~Point() {} // destructor};
Point p1; // default: (0, 0)Point p2(3, 4); // parameterized: (3, 4)Point p3(p2); // copy: (3, 4)RFC 959, Section Object-Oriented Programming — "cppreference.com"
The this Pointer
Section titled “The this Pointer”The this pointer is an implicit pointer available inside member functions that points to the calling object.
class Box { int size;public: Box& setSize(int size) { this->size = size; // distinguishes member from parameter return *this; // enables method chaining }};RFC 959, Section Object-Oriented Programming — "cppreference.com"
Encapsulation
Section titled “Encapsulation”Encapsulation bundles data and the functions that operate on it into a single class, restricting direct access to internal state through access specifiers. External code interacts with the object through getters and setters.
class Temperature { double celsius; // private by defaultpublic: void set(double c) { if (c >= -273.15) // validation logic celsius = c; } double get() const { return celsius; } double fahrenheit() const { return celsius * 9.0 / 5.0 + 32; }};RFC 959, Section Pillars of OOPs
static Members
Section titled “static Members”static class members belong to the class itself, not to any specific object. Static data members are shared across all instances. Static member functions can be called without an object.
class Counter { static int count; // declarationpublic: Counter() { count++; } ~Counter() { count--; } static int getCount() { return count; } // no this pointer};
int Counter::count = 0; // definition (required, usually in .cpp)
Counter a, b, c;cout << Counter::getCount(); // 3Other Uses of static
Section titled “Other Uses of static”| Context | Effect |
|---|---|
static local variable | Persists across function calls, initialized once |
static global variable/function | Internal linkage — visible only in the current translation unit |
static class member | Shared across all instances of the class |
void counter() { static int n = 0; // initialized once, persists across calls cout << ++n << " ";}counter(); counter(); counter(); // 1 2 3RFC 959, Section static Members — "cppreference.com"
Inheritance
Section titled “Inheritance”Inheritance allows a derived class to acquire the properties and behavior of a base class, promoting code reuse.
Single Inheritance
Section titled “Single Inheritance”class Animal {public: string name; void eat() { cout << name << " eats" << endl; }};
class Dog : public Animal {public: void bark() { cout << name << " barks" << endl; }};
Dog d;d.name = "Rex";d.eat(); // Rex eatsd.bark(); // Rex barksMultiple Inheritance
Section titled “Multiple Inheritance”A class can inherit from more than one base class.
class Printable {public: void print() { cout << "Printing..." << endl; }};
class Scannable {public: void scan() { cout << "Scanning..." << endl; }};
class Printer : public Printable, public Scannable {};
Printer p;p.print(); // Printing...p.scan(); // Scanning...Access Specifiers in Inheritance
Section titled “Access Specifiers in Inheritance”The inheritance access specifier controls how base class members are exposed in the derived class.
| Base member | public inheritance | protected inheritance | private inheritance |
|---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | Not accessible | Not accessible | Not accessible |
Method Overriding
Section titled “Method Overriding”A derived class can override a base class method by defining a function with the same signature.
class Shape {public: void draw() { cout << "Drawing shape" << endl; }};
class Circle : public Shape {public: void draw() { cout << "Drawing circle" << endl; }};
Circle c;c.draw(); // Drawing circleRFC 959, Section Pillars of OOPs — "cppreference.com"
friend Keyword
Section titled “friend Keyword”A friend declaration grants a non-member function or another class access to private and protected members.
class Box { double width;public: Box(double w) : width(w) {} friend void printWidth(const Box& b); // friend function friend class BoxFactory; // friend class};
void printWidth(const Box& b) { cout << b.width; // can access private member}Use friend sparingly — it breaks encapsulation. Common legitimate uses: operator overloading (e.g., operator<<) and factory classes.
RFC 959, Section friend — "cppreference.com"
Virtual Inheritance
Section titled “Virtual Inheritance”When a class inherits from two bases that share a common ancestor, the diamond problem creates two copies of the ancestor’s members. Virtual inheritance ensures only one copy exists.
class Animal { public: string name; };
class Mammal : virtual public Animal {}; // virtualclass WingedAnimal : virtual public Animal {}; // virtual
class Bat : public Mammal, public WingedAnimal {};
Bat b;b.name = "Bruce"; // OK — only one copy of Animal::nameWithout virtual, b.name would be ambiguous (two copies of Animal).
RFC 959, Section Virtual Inheritance — "cppreference.com"
Polymorphism
Section titled “Polymorphism”Polymorphism allows one interface to represent different underlying types. C++ supports both compile-time and runtime polymorphism.
Function Overloading (Compile-Time)
Section titled “Function Overloading (Compile-Time)”Multiple functions can share the same name if they differ in parameter types or count.
int add(int a, int b) { return a + b; }double add(double a, double b) { return a + b; }int add(int a, int b, int c) { return a + b + c; }Operator Overloading
Section titled “Operator Overloading”Class-specific behavior for operators is defined using the operator keyword.
class Vec2 {public: double x, y; Vec2(double x, double y) : x(x), y(y) {}
Vec2 operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); }};
Vec2 a(1, 2), b(3, 4);Vec2 c = a + b; // (4, 6)Virtual Functions (Runtime Polymorphism)
Section titled “Virtual Functions (Runtime Polymorphism)”A virtual function in the base class allows derived classes to provide their own implementation, resolved at runtime through a base pointer or reference.
class Shape {public: virtual void draw() { cout << "Shape" << endl; } virtual ~Shape() {} // virtual destructor};
class Circle : public Shape {public: void draw() override { cout << "Circle" << endl; }};
Shape* s = new Circle();s->draw(); // Circle (resolved at runtime)delete s;Abstract Classes and Pure Virtual Functions
Section titled “Abstract Classes and Pure Virtual Functions”A pure virtual function has no implementation in the base class. A class with at least one pure virtual function is an abstract class and cannot be instantiated. This is the C++ equivalent of an interface.
class Drawable {public: virtual void draw() = 0; // pure virtual virtual ~Drawable() {}};
class Square : public Drawable {public: void draw() override { cout << "Drawing square" << endl; }};
// Drawable d; // ERROR: cannot instantiate abstract classSquare sq;sq.draw(); // Drawing squareRFC 959, Section Pillars of OOPs — "cppreference.com"
Structs
Section titled “Structs”A struct is identical to a class except that its members are public by default (class members are private by default).
struct Point { double x, y; // public by default
double distance() const { return sqrt(x * x + y * y); }};
Point p = {3.0, 4.0};cout << p.distance(); // 5| Feature | struct | class |
|---|---|---|
| Default access | public | private |
| Default inheritance | public | private |
| Convention | Plain data aggregates | Objects with behavior |
RFC 959, Section Structs — "cppreference.com"
Enums define a set of named integer constants.
Traditional Enums
Section titled “Traditional Enums”enum Color { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2
Color c = GREEN;cout << c; // 1Traditional enums are unscoped — their values leak into the enclosing scope and implicitly convert to int.
Scoped Enums (enum class)
Section titled “Scoped Enums (enum class)”Scoped enums (C++11) provide type safety and prevent implicit conversions.
enum class Direction { UP, DOWN, LEFT, RIGHT };
Direction d = Direction::UP;// int n = d; // ERROR: no implicit conversionint n = static_cast<int>(d); // explicit conversion: 0RFC 959, Section Enums — "cppreference.com"
Templates
Section titled “Templates”Templates enable writing generic code that works with any data type. The compiler generates type-specific versions at compile time.
Function Templates
Section titled “Function Templates”template <typename T>T maximum(T a, T b) { return (a > b) ? a : b;}
cout << maximum(3, 7); // 7 (int)cout << maximum(3.5, 2.1); // 3.5 (double)Class Templates
Section titled “Class Templates”template <typename T>class Stack { vector<T> data;public: void push(const T& val) { data.push_back(val); } T pop() { T top = data.back(); data.pop_back(); return top; } bool empty() const { return data.empty(); }};
Stack<int> intStack;intStack.push(42);RFC 959, Section Templates — "cppreference.com"
Exception Handling
Section titled “Exception Handling”C++ handles runtime errors with try, catch, and throw. When an error occurs, throw creates an exception that propagates up the call stack until a matching catch block is found.
try / catch / throw
Section titled “try / catch / throw”try { int age = -1; if (age < 0) throw invalid_argument("Age cannot be negative");} catch (const invalid_argument& e) { cout << "Error: " << e.what() << endl;} catch (const exception& e) { cout << "General error: " << e.what() << endl;} catch (...) { cout << "Unknown error" << endl;}Catch blocks are matched top-to-bottom — put more specific types first. Always catch by const& to avoid slicing and unnecessary copies.
Standard Exception Hierarchy
Section titled “Standard Exception Hierarchy”All standard exceptions inherit from std::exception. The two main branches are logic_error (programmer mistakes) and runtime_error (external failures).
| Exception | Header | Use |
|---|---|---|
std::exception | <exception> | Base class for all standard exceptions |
std::logic_error | <stdexcept> | Errors due to faulty logic (preventable bugs) |
std::invalid_argument | <stdexcept> | Invalid function arguments |
std::out_of_range | <stdexcept> | Index out of bounds |
std::runtime_error | <stdexcept> | Errors detectable only at runtime |
std::overflow_error | <stdexcept> | Arithmetic overflow |
std::bad_alloc | <new> | Memory allocation failure |
std::bad_cast | <typeinfo> | Failed dynamic_cast on references |
Custom Exception Hierarchies
Section titled “Custom Exception Hierarchies”For real projects, define a project-level base exception that inherits from a standard exception, then derive specific error types from it. This lets callers catch all project errors with one type, or handle specific errors individually.
#pragma once#include <stdexcept>#include <string>
namespace ftp {
class FtpException : public std::runtime_error {public: explicit FtpException(const std::string& msg) : std::runtime_error(msg) {}};
class ArgsException : public FtpException {public: explicit ArgsException(const std::string& msg) : FtpException(msg) {}};
class UsageError : public ArgsException {public: UsageError() : ArgsException("Usage: ./my_ftp <port> <path>") {}};
class ParsePortError : public ArgsException {public: ParsePortError() : ArgsException("port must be a number") {}};
class InvalidPortError : public ArgsException {public: InvalidPortError() : ArgsException("Port must be between 1024 and 65535") {}};
} // namespace ftpThis hierarchy allows granular catching:
try { ftp::Server server(argc, argv); server.run();} catch (const ftp::ArgsException& e) { cerr << "Argument error: " << e.what() << endl; return 1;} catch (const ftp::FtpException& e) { cerr << "FTP error: " << e.what() << endl; return 1;} catch (const std::exception& e) { cerr << "Unexpected error: " << e.what() << endl; return 1;}noexcept
Section titled “noexcept”Mark functions noexcept when they are guaranteed not to throw. If a noexcept function does throw, the program calls std::terminate immediately.
int size() const noexcept { return n; } // simple getter, cannot failvoid swap(Buffer& other) noexcept; // swap should never throw~MyClass() noexcept; // destructors are noexcept by defaultBuffer(Buffer&& other) noexcept; // move operations should be noexceptMark noexcept | Do NOT mark noexcept |
|---|---|
| Destructors | Functions that allocate memory |
| Move constructors/assignment | Functions that do I/O |
| Swap functions | Functions that call potentially-throwing code |
| Simple getters/setters | Virtual functions that subclasses may override with throwing code |
Rethrowing Exceptions
Section titled “Rethrowing Exceptions”Use bare throw; inside a catch block to rethrow the current exception without slicing it.
try { riskyOperation();} catch (const std::exception& e) { logError(e.what()); // log it throw; // rethrow original exception (preserves type) // throw e; // BAD: slices to std::exception, loses derived type}Best Practices
Section titled “Best Practices”| Do | Don’t |
|---|---|
Throw by value, catch by const& | Catch by value (causes slicing) |
| Use exceptions for actual errors | Use exceptions for control flow |
| Build a project exception hierarchy | Throw strings or ints |
| Clean up resources with RAII | Use manual try/catch for cleanup |
Mark non-throwing functions noexcept | Mark everything noexcept optimistically |
| Catch at the level that can handle the error | Catch and silently ignore |
| Let exceptions propagate when you can’t recover | Catch and rethrow with throw e; (slices) |
RFC 959, Section Exception Handling — "cppreference.com"
RFC 959, Section E: Error handling — "C++ Core Guidelines"
Lambda Expressions
Section titled “Lambda Expressions”A lambda expression (C++11) creates an anonymous function object inline. The syntax is [capture](parameters) -> return_type { body }.
auto greet = []() { cout << "Hello" << endl; };greet(); // Hello
auto add = [](int a, int b) { return a + b; };cout << add(3, 4); // 7Capture Clauses
Section titled “Capture Clauses”The capture clause [] specifies which variables from the enclosing scope the lambda can access.
| Capture | Meaning |
|---|---|
[] | Capture nothing |
[=] | Capture all local variables by value |
[&] | Capture all local variables by reference |
[x] | Capture x by value |
[&x] | Capture x by reference |
[=, &x] | All by value except x by reference |
int factor = 3;auto multiply = [factor](int x) { return x * factor; };cout << multiply(5); // 15
auto increment = [&factor]() { factor++; };increment();cout << factor; // 4RFC 959, Section Lambda Expressions — "cppreference.com"
Dynamic Memory
Section titled “Dynamic Memory”C++ allocates memory on the heap using new and releases it with delete. Forgetting to delete causes memory leaks.
// Single objectint* p = new int(42);cout << *p; // 42delete p;
// Arrayint* arr = new int[5]{1, 2, 3, 4, 5};cout << arr[2]; // 3delete[] arr;RFC 959, Section Dynamic Memory — "cppreference.com"
Smart Pointers
Section titled “Smart Pointers”Smart pointers (C++11, <memory>) automate memory management by destroying the owned object when the pointer goes out of scope. They eliminate manual new/delete and the bugs that come with it.
Which Smart Pointer to Use?
Section titled “Which Smart Pointer to Use?”| Smart Pointer | Ownership | Copy? | Use When |
|---|---|---|---|
unique_ptr | Exclusive (one owner) | No (move only) | Default choice. One clear owner. |
shared_ptr | Shared (reference counted) | Yes | Multiple owners need the same object |
weak_ptr | Non-owning observer | N/A | Break circular references, optional access to shared object |
unique_ptr
Section titled “unique_ptr”unique_ptr owns an object exclusively — it cannot be copied, only moved. This is the default smart pointer you should reach for.
#include <memory>
// Createauto p = make_unique<int>(42); // preferredunique_ptr<int> p2(new int(42)); // also works
// Use — just like a raw pointercout << *p; // 42*p = 100;
// Transfer ownershipunique_ptr<int> p3 = move(p); // p is now nullptr// unique_ptr<int> p4 = p3; // ERROR: cannot copy
// unique_ptr with arraysauto arr = make_unique<int[]>(5); // array of 5 intsarr[0] = 10;| Method | Description |
|---|---|
*ptr | Dereference (access value) |
ptr->member | Access member of pointed-to object |
ptr.get() | Get raw pointer (non-owning) |
ptr.reset() | Delete owned object, set to nullptr |
ptr.reset(new_ptr) | Delete owned, take ownership of new_ptr |
ptr.release() | Release ownership, return raw pointer (caller must delete) |
move(ptr) | Transfer ownership to another unique_ptr |
if (ptr) | Check if non-null |
Common pattern — factory functions:
class Widget { /* ... */ };
unique_ptr<Widget> createWidget(int type) { if (type == 1) return make_unique<WidgetA>(); if (type == 2) return make_unique<WidgetB>(); return nullptr;}
auto w = createWidget(1); // caller owns the widgetshared_ptr
Section titled “shared_ptr”shared_ptr allows multiple pointers to share ownership of an object. An internal reference count tracks how many shared_ptrs point to the object. The object is destroyed when the last one is destroyed or reset.
auto a = make_shared<int>(10);cout << a.use_count(); // 1
{ shared_ptr<int> b = a; // reference count: 2 shared_ptr<int> c = a; // reference count: 3 cout << a.use_count(); // 3} // b and c destroyed, count drops to 1
cout << a.use_count(); // 1// a destroyed at end of scope, object deleted| Method | Description |
|---|---|
ptr.use_count() | Current reference count |
ptr.unique() | True if use_count() == 1 (deprecated C++17, removed C++20) |
ptr.reset() | Release this pointer’s ownership (decrements count) |
ptr.get() | Get raw pointer |
weak_ptr
Section titled “weak_ptr”weak_ptr observes an object owned by shared_ptr without affecting the reference count. Used to break circular references that would otherwise leak memory.
shared_ptr<int> sp = make_shared<int>(5);weak_ptr<int> wp = sp;
cout << wp.use_count(); // 1 (counts shared_ptrs only)cout << wp.expired(); // false
// Must lock() to access the value — returns shared_ptr or nullptrif (auto locked = wp.lock()) { cout << *locked; // 5}
sp.reset(); // object destroyedcout << wp.expired(); // trueauto locked = wp.lock(); // returns nullptrCircular reference problem:
struct Node { shared_ptr<Node> next; // if both nodes point to each other, // neither is ever deleted (reference count never reaches 0)};
// Fix: use weak_ptr for back-referencesstruct Node { shared_ptr<Node> next; weak_ptr<Node> prev; // does not prevent deletion};Smart Pointers with Polymorphism
Section titled “Smart Pointers with Polymorphism”Smart pointers work naturally with base/derived classes and virtual functions.
class Shape {public: virtual double area() const = 0; virtual ~Shape() = default;};
class Circle : public Shape { double r;public: Circle(double r) : r(r) {} double area() const override { return 3.14159 * r * r; }};
// Store derived types through base pointervector<unique_ptr<Shape>> shapes;shapes.push_back(make_unique<Circle>(5.0));
for (auto& s : shapes) cout << s->area() << endl; // 78.5397 — virtual dispatch worksSmart Pointer Best Practices
Section titled “Smart Pointer Best Practices”| Do | Don’t |
|---|---|
Use make_unique / make_shared | Use new directly with smart pointers |
Default to unique_ptr | Default to shared_ptr “just in case” |
Pass unique_ptr by value to transfer ownership | Pass smart pointers by reference when ownership isn’t changing |
| Pass raw pointer or reference when function doesn’t affect lifetime | Pass shared_ptr to every function (spreads reference counting overhead) |
Use weak_ptr for caches and back-references | Create circular shared_ptr references |
Use unique_ptr for polymorphic containers | Use raw new/delete for polymorphic objects |
RFC 959, Section Smart Pointers — "cppreference.com"
Move Semantics
Section titled “Move Semantics”Move semantics (C++11) transfer resources from one object to another instead of copying. An rvalue reference (T&&) binds to temporaries and objects about to be destroyed.
Move Constructor and Move Assignment
Section titled “Move Constructor and Move Assignment”class Buffer { int* data; size_t size;public: Buffer(size_t n) : data(new int[n]), size(n) {} ~Buffer() { delete[] data; }
// Copy — expensive Buffer(const Buffer& other) : data(new int[other.size]), size(other.size) { copy(other.data, other.data + size, data); }
// Move — cheap, steals resources Buffer(Buffer&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; other.size = 0; }
// Move assignment Buffer& operator=(Buffer&& other) noexcept { if (this != &other) { delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; } return *this; }};std::move
Section titled “std::move”std::move casts an lvalue to an rvalue reference, enabling the move constructor or move assignment.
Buffer a(1000);Buffer b = std::move(a); // moves a's resources to b; a is now emptyRFC 959, Section Move Semantics — "cppreference.com"
Resource Acquisition Is Initialization is the core C++ idiom for resource management. Resources (memory, files, locks, sockets) are acquired in the constructor and released in the destructor. When the object goes out of scope, cleanup happens automatically — no manual release needed.
class FileHandle { FILE* f;public: FileHandle(const char* path) : f(fopen(path, "r")) { if (!f) throw runtime_error("Cannot open file"); } ~FileHandle() { if (f) fclose(f); } // automatic cleanup
FileHandle(const FileHandle&) = delete; // prevent copying FileHandle& operator=(const FileHandle&) = delete;};
void readConfig() { FileHandle config("app.conf"); // ... use config ...} // config.~FileHandle() called automatically, file closedThe standard library uses RAII everywhere: vector manages heap memory, unique_ptr manages owned objects, lock_guard manages mutexes, fstream manages file handles.
RFC 959, Section RAII — "cppreference.com"
Data Structures (STL Containers)
Section titled “Data Structures (STL Containers)”The Standard Template Library provides generic container classes for every common data structure. All containers are templates — they work with any type.
Which Container to Use?
Section titled “Which Container to Use?”| Need | Container | Why |
|---|---|---|
| Dynamic array, general purpose | vector | Contiguous memory, fast random access, cache-friendly |
| Fixed-size array | array | No heap allocation, bounds-checkable with .at() |
| FIFO queue | queue | push to back, pop from front |
| LIFO stack | stack | push and pop from top |
| Priority queue / heap | priority_queue | Always gives you the largest (or smallest) element |
| Fast insert/remove at both ends | deque | Like vector but O(1) push/pop at front too |
| Fast insert/remove anywhere | list | Doubly linked list, O(1) splice and insert at iterator |
| Key-value lookup | map or unordered_map | Sorted keys (map) or O(1) average lookup (unordered) |
| Unique collection | set or unordered_set | Sorted (set) or O(1) average lookup (unordered) |
| Sorted data with duplicates | multiset / multimap | Like set/map but allows duplicate keys |
vector
Section titled “vector”Dynamic array. Elements stored contiguously in memory. The default choice for most situations.
#include <vector>
vector<int> v = {1, 2, 3};v.push_back(4); // {1, 2, 3, 4}v.pop_back(); // {1, 2, 3}v.insert(v.begin(), 0); // {0, 1, 2, 3}v.erase(v.begin() + 1); // {0, 2, 3}cout << v[0]; // 0cout << v.at(1); // 2 (bounds-checked)cout << v.size(); // 3cout << v.empty(); // 0 (false)v.clear(); // {}| Method | Complexity | Description |
|---|---|---|
push_back(val) | Amortized O(1) | Add to end |
pop_back() | O(1) | Remove from end |
operator[] / at(i) | O(1) | Access by index (at throws on out-of-range) |
insert(pos, val) | O(n) | Insert at iterator position |
erase(pos) | O(n) | Remove at iterator position |
size() / empty() | O(1) | Element count / emptiness check |
front() / back() | O(1) | First / last element |
clear() | O(n) | Remove all elements |
reserve(n) | O(n) | Pre-allocate capacity to avoid reallocations |
shrink_to_fit() | O(n) | Release unused capacity |
Fixed-size array (C++11). Size is a compile-time constant. No heap allocation. Safer alternative to C-style arrays.
#include <array>
array<int, 4> a = {10, 20, 30, 40};cout << a[2]; // 30cout << a.at(5); // throws std::out_of_rangecout << a.size(); // 4a.fill(0); // {0, 0, 0, 0}Double-ended queue. Like vector but supports O(1) push/pop at both front and back. Elements are not stored contiguously.
#include <deque>
deque<int> dq = {2, 3, 4};dq.push_front(1); // {1, 2, 3, 4}dq.push_back(5); // {1, 2, 3, 4, 5}dq.pop_front(); // {2, 3, 4, 5}dq.pop_back(); // {2, 3, 4}cout << dq[1]; // 3 (random access)| Method | Complexity |
|---|---|
push_front(val) / push_back(val) | Amortized O(1) |
pop_front() / pop_back() | O(1) |
operator[] / at(i) | O(1) |
insert(pos, val) / erase(pos) | O(n) |
Doubly linked list. Fast insert/remove at any position given an iterator, but no random access.
#include <list>
list<int> lst = {1, 2, 3};lst.push_front(0); // {0, 1, 2, 3}lst.push_back(4); // {0, 1, 2, 3, 4}
auto it = lst.begin();advance(it, 2); // move iterator to index 2lst.insert(it, 99); // {0, 1, 99, 2, 3, 4}lst.erase(it); // {0, 1, 99, 3, 4}
lst.sort(); // {0, 1, 3, 4, 99}lst.reverse(); // {99, 4, 3, 1, 0}lst.remove(3); // {99, 4, 1, 0}| Method | Complexity |
|---|---|
push_front / push_back | O(1) |
insert(it, val) / erase(it) | O(1) at known position |
sort() | O(n log n) |
remove(val) | O(n) |
splice(pos, other_list) | O(1) — moves nodes without copying |
LIFO (Last In, First Out) adaptor. Wraps deque by default.
#include <stack>
stack<int> st;st.push(10);st.push(20);st.push(30);
cout << st.top(); // 30st.pop();cout << st.top(); // 20cout << st.size(); // 2cout << st.empty(); // 0 (false)| Method | Complexity | Description |
|---|---|---|
push(val) | O(1) | Add to top |
pop() | O(1) | Remove from top (does NOT return value) |
top() | O(1) | View top element |
size() / empty() | O(1) | Element count / emptiness check |
FIFO (First In, First Out) adaptor. Wraps deque by default.
#include <queue>
queue<int> q;q.push(10);q.push(20);q.push(30);
cout << q.front(); // 10cout << q.back(); // 30q.pop();cout << q.front(); // 20cout << q.size(); // 2| Method | Complexity | Description |
|---|---|---|
push(val) | O(1) | Add to back |
pop() | O(1) | Remove from front (does NOT return value) |
front() / back() | O(1) | View front / back element |
size() / empty() | O(1) | Element count / emptiness check |
priority_queue
Section titled “priority_queue”Max-heap by default — top() always returns the largest element.
#include <queue>
priority_queue<int> pq;pq.push(3);pq.push(1);pq.push(4);pq.push(1);pq.push(5);
cout << pq.top(); // 5pq.pop();cout << pq.top(); // 4
// Min-heap: reverse the orderingpriority_queue<int, vector<int>, greater<int>> minPq;minPq.push(3); minPq.push(1); minPq.push(4);cout << minPq.top(); // 1| Method | Complexity | Description |
|---|---|---|
push(val) | O(log n) | Insert element |
pop() | O(log n) | Remove top element |
top() | O(1) | View top (largest by default) element |
Ordered key-value store. Keys are unique and sorted. Implemented as a red-black tree.
#include <map>
map<string, int> ages;ages["Alice"] = 30;ages["Bob"] = 25;ages.insert({"Charlie", 35});
cout << ages["Alice"]; // 30cout << ages.at("Bob"); // 25 (throws if key missing)cout << ages.count("Eve"); // 0 (not found)
ages.erase("Bob");
for (auto& [name, age] : ages) cout << name << ": " << age << endl;// Alice: 30, Charlie: 35 (sorted by key)
auto it = ages.find("Alice");if (it != ages.end()) cout << it->second; // 30| Method | Complexity | Description |
|---|---|---|
operator[key] | O(log n) | Access/insert (creates default if missing) |
at(key) | O(log n) | Access (throws out_of_range if missing) |
insert({k, v}) | O(log n) | Insert if key doesn’t exist |
erase(key) / erase(it) | O(log n) | Remove by key or iterator |
find(key) | O(log n) | Returns iterator (or end() if not found) |
count(key) | O(log n) | Returns 0 or 1 |
size() / empty() | O(1) | Element count / emptiness check |
unordered_map
Section titled “unordered_map”Hash map. Same interface as map but O(1) average lookup instead of O(log n). Keys are not sorted.
#include <unordered_map>
unordered_map<string, int> scores;scores["Alice"] = 95;scores["Bob"] = 87;
// Same API as map: [], at(), find(), erase(), count(), size()map | unordered_map | |
|---|---|---|
| Lookup | O(log n) | O(1) average, O(n) worst |
| Insertion | O(log n) | O(1) average |
| Ordered iteration | Yes (by key) | No |
| Memory | Less | More (hash table overhead) |
| Use when | Need sorted keys or range queries | Need fastest lookup |
Ordered unique collection. Elements are sorted and deduplicated. Implemented as a red-black tree.
#include <set>
set<int> s = {3, 1, 4, 1, 5, 9, 2, 6};// s = {1, 2, 3, 4, 5, 6, 9} — sorted, duplicates removed
s.insert(7); // {1, 2, 3, 4, 5, 6, 7, 9}s.erase(4); // {1, 2, 3, 5, 6, 7, 9}cout << s.count(3); // 1 (present)cout << s.count(4); // 0 (removed)
auto it = s.find(5);if (it != s.end()) cout << *it; // 5
// Range: elements >= 3 and < 7auto lo = s.lower_bound(3); // iterator to 3auto hi = s.lower_bound(7); // iterator to 7for (auto it = lo; it != hi; ++it) cout << *it << " "; // 3 5 6| Method | Complexity | Description |
|---|---|---|
insert(val) | O(log n) | Add element (ignored if duplicate) |
erase(val) / erase(it) | O(log n) | Remove element |
find(val) | O(log n) | Returns iterator or end() |
count(val) | O(log n) | Returns 0 or 1 |
lower_bound(val) | O(log n) | Iterator to first element >= val |
upper_bound(val) | O(log n) | Iterator to first element > val |
unordered_set provides the same interface with O(1) average operations but no ordering.
multimap and multiset
Section titled “multimap and multiset”Like map and set but allow duplicate keys/values.
#include <map>#include <set>
multimap<string, int> grades;grades.insert({"Alice", 90});grades.insert({"Alice", 85}); // duplicate key OKgrades.insert({"Bob", 92});
cout << grades.count("Alice"); // 2
// Iterate all values for a keyauto [lo, hi] = grades.equal_range("Alice");for (auto it = lo; it != hi; ++it) cout << it->second << " "; // 90 85
multiset<int> ms = {1, 1, 2, 3, 3, 3};cout << ms.count(3); // 3pair and tuple
Section titled “pair and tuple”pair holds two values. tuple holds any number of values. Both are in <utility> and <tuple>.
#include <utility>#include <tuple>
pair<string, int> p = {"Alice", 30};cout << p.first << " " << p.second; // Alice 30
tuple<int, double, string> t = {1, 3.14, "hello"};cout << get<0>(t); // 1cout << get<2>(t); // hello
// Structured bindings (C++17)auto [name, age] = p;auto [x, y, z] = t;bitset
Section titled “bitset”Fixed-size bit array for compact boolean storage and bitwise operations. Size is a compile-time constant.
#include <bitset>
bitset<8> b("10110011");cout << b; // 10110011cout << b.count(); // 5 (number of 1-bits)cout << b.test(0); // 1 (bit at position 0)b.flip(); // 01001100b.set(7); // 11001100b.reset(7); // 01001100cout << b.to_ulong(); // 76Container Complexity Summary
Section titled “Container Complexity Summary”| Container | Access | Insert/Remove (end) | Insert/Remove (middle) | Find |
|---|---|---|---|---|
vector | O(1) | Amortized O(1) | O(n) | O(n) |
deque | O(1) | O(1) both ends | O(n) | O(n) |
list | O(n) | O(1) both ends | O(1) at iterator | O(n) |
stack / queue | O(1) top/front | O(1) | N/A | N/A |
priority_queue | O(1) top | O(log n) | N/A | N/A |
map / set | O(log n) | O(log n) | O(log n) | O(log n) |
unordered_map / set | O(1) avg | O(1) avg | O(1) avg | O(1) avg |
RFC 959, Section STL Containers — "cppreference.com"
Iterators and STL Algorithms
Section titled “Iterators and STL Algorithms”Iterators
Section titled “Iterators”Iterators are the standard way to traverse containers. Every STL container provides begin() and end() iterators.
vector<int> v = {10, 20, 30, 40};
// Iterator loopfor (auto it = v.begin(); it != v.end(); ++it) { cout << *it << " ";}
// Range-based for (preferred)for (int x : v) cout << x << " ";
// Reverse iterationfor (auto it = v.rbegin(); it != v.rend(); ++it) { cout << *it << " ";}Common STL Algorithms
Section titled “Common STL Algorithms”Include <algorithm> and <numeric>. Algorithms operate on iterator ranges [begin, end).
| Algorithm | Description | Example |
|---|---|---|
sort(b, e) | Sort range ascending | sort(v.begin(), v.end()) |
sort(b, e, cmp) | Sort with custom comparator | sort(v.begin(), v.end(), greater<int>()) |
find(b, e, val) | Find first occurrence | auto it = find(v.begin(), v.end(), 42) |
count(b, e, val) | Count occurrences | int n = count(v.begin(), v.end(), 0) |
reverse(b, e) | Reverse range in place | reverse(v.begin(), v.end()) |
accumulate(b, e, init) | Sum of range (<numeric>) | int sum = accumulate(v.begin(), v.end(), 0) |
transform(b, e, out, fn) | Apply function to each element | transform(v.begin(), v.end(), v.begin(), [](int x){ return x*2; }) |
remove_if(b, e, pred) | Move non-matching to front | auto it = remove_if(v.begin(), v.end(), [](int x){ return x < 0; }) |
unique(b, e) | Remove consecutive duplicates | auto it = unique(v.begin(), v.end()) |
binary_search(b, e, val) | Check if value exists (sorted) | bool found = binary_search(v.begin(), v.end(), 42) |
min_element(b, e) | Iterator to smallest element | auto it = min_element(v.begin(), v.end()) |
max_element(b, e) | Iterator to largest element | auto it = max_element(v.begin(), v.end()) |
for_each(b, e, fn) | Apply function to each element | for_each(v.begin(), v.end(), [](int x){ cout << x; }) |
#include <algorithm>#include <numeric>
vector<int> v = {5, 2, 8, 1, 9, 3};
sort(v.begin(), v.end()); // {1, 2, 3, 5, 8, 9}reverse(v.begin(), v.end()); // {9, 8, 5, 3, 2, 1}
int sum = accumulate(v.begin(), v.end(), 0); // 28auto it = find(v.begin(), v.end(), 5); // iterator to 5bool has3 = binary_search(v.begin(), v.end(), 3); // requires sorted
// Erase-remove idiomv.erase(remove_if(v.begin(), v.end(), [](int x) { return x < 3; }), v.end());RFC 959, Section STL Algorithms — "cppreference.com"
Type Casting
Section titled “Type Casting”C++ provides four named cast operators that replace C-style casts with explicit intent.
| Cast | Purpose |
|---|---|
static_cast<T> | Compile-time conversions between compatible types |
dynamic_cast<T> | Safe downcasting in class hierarchies (requires virtual functions) |
const_cast<T> | Add or remove const qualifier |
reinterpret_cast<T> | Bit-level reinterpretation between unrelated types |
// static_cast — numeric conversiondouble pi = 3.14;int n = static_cast<int>(pi); // 3
// dynamic_cast — safe downcastclass Base { public: virtual ~Base() {} };class Derived : public Base { public: void hello() {} };
Base* b = new Derived();Derived* d = dynamic_cast<Derived*>(b); // succeedsif (d) d->hello();delete b;
// const_cast — remove constconst int val = 10;int* mutable_ptr = const_cast<int*>(&val);
// reinterpret_cast — raw reinterpretationint x = 42;void* vp = reinterpret_cast<void*>(&x);RFC 959, Section Type Casting — "cppreference.com"
Namespaces
Section titled “Namespaces”Namespaces group related declarations under a named scope to prevent name collisions.
namespace Math { const double PI = 3.14159265; double square(double x) { return x * x; }}
// Qualified accesscout << Math::PI;cout << Math::square(5);
// Using directive — brings all names into scopeusing namespace Math;cout << PI;
// Using declaration — brings a single name into scopeusing Math::square;cout << square(3);RFC 959, Section Namespaces — "cppreference.com"
Preprocessor Directives
Section titled “Preprocessor Directives”The preprocessor processes source files before compilation. Directives start with #.
| Directive | Purpose |
|---|---|
#include <file> | Include a standard header |
#include "file" | Include a local header |
#define NAME value | Define a macro constant |
#define F(x) expr | Define a function-like macro |
#ifdef NAME | Compile block if NAME is defined |
#ifndef NAME | Compile block if NAME is not defined |
#endif | End conditional compilation block |
#pragma once | Include guard (non-standard but widely supported) |
#ifndef CONFIG_H#define CONFIG_H
#define MAX_SIZE 100#define SQUARE(x) ((x) * (x))
#ifdef DEBUG #define LOG(msg) cout << msg << endl#else #define LOG(msg)#endif
#endifRFC 959, Section Preprocessor Directives — "cppreference.com"
auto and Type Deduction
Section titled “auto and Type Deduction”The auto keyword (C++11) lets the compiler deduce a variable’s type from its initializer.
auto x = 42; // intauto pi = 3.14; // doubleauto name = "hello"s; // std::string (with using namespace std::string_literals)auto v = vector<int>{1, 2, 3};
// With iterators — avoids verbose type namesmap<string, vector<int>> data;for (auto& [key, values] : data) { // structured binding (C++17) for (auto val : values) { cout << key << ": " << val << endl; }}Structured Bindings (C++17)
Section titled “Structured Bindings (C++17)”Decompose structs, pairs, tuples, and arrays into named variables.
pair<string, int> p = {"Alice", 30};auto [name, age] = p;
map<string, int> scores = {{"A", 90}, {"B", 80}};for (auto& [name, score] : scores) cout << name << ": " << score << endl;
auto [x, y, z] = tuple{1, 2.0, "three"};RFC 959, Section auto — "cppreference.com"
Modern C++ Features
Section titled “Modern C++ Features”std::optional (C++17)
Section titled “std::optional (C++17)”Represents a value that may or may not be present. Replaces the “return -1 or nullptr on failure” pattern.
#include <optional>
optional<int> findIndex(const vector<int>& v, int target) { for (int i = 0; i < v.size(); i++) if (v[i] == target) return i; return nullopt;}
auto idx = findIndex({10, 20, 30}, 20);if (idx) cout << "Found at " << *idx; // Found at 1cout << idx.value_or(-1); // 1std::variant (C++17)
Section titled “std::variant (C++17)”A type-safe union that holds one of several types.
#include <variant>
variant<int, double, string> val = "hello";cout << get<string>(val); // hello
val = 42;cout << get<int>(val); // 42
// Visit patternvisit([](auto&& arg) { cout << arg; }, val);std::any (C++17)
Section titled “std::any (C++17)”Holds any type — like void* but type-safe.
#include <any>
any a = 42;cout << any_cast<int>(a); // 42a = string("hello");cout << any_cast<string>(a); // hellostd::string_view (C++17)
Section titled “std::string_view (C++17)”A lightweight, non-owning reference to a string. Avoids copies when you only need to read.
#include <string_view>
void print(string_view sv) { // accepts string, const char*, string_view cout << sv << " (" << sv.size() << " chars)" << endl;}
print("hello"); // no allocationstring s = "world";print(s); // no copyprint(string_view(s).substr(0, 3)); // "wor", no allocationstd::function and Callbacks
Section titled “std::function and Callbacks”std::function is a general-purpose function wrapper that can hold any callable.
#include <functional>
function<int(int, int)> op;
op = [](int a, int b) { return a + b; };cout << op(3, 4); // 7
op = [](int a, int b) { return a * b; };cout << op(3, 4); // 12
// As callback parametervoid repeat(int n, function<void()> fn) { for (int i = 0; i < n; i++) fn();}repeat(3, []() { cout << "Hi "; }); // Hi Hi HiRFC 959, Section Modern C++ Features — "cppreference.com"
Multithreading
Section titled “Multithreading”C++11 introduced built-in threading support in <thread>, <mutex>, and <future>.
Creating Threads
Section titled “Creating Threads”#include <thread>
void work(int id) { cout << "Thread " << id << " running" << endl;}
thread t1(work, 1);thread t2(work, 2);t1.join(); // wait for t1 to finisht2.join(); // wait for t2 to finishMutex and Lock Guard
Section titled “Mutex and Lock Guard”A mutex prevents data races when multiple threads access shared data. lock_guard locks the mutex on construction and unlocks on destruction (RAII).
#include <mutex>
mutex mtx;int counter = 0;
void increment(int times) { for (int i = 0; i < times; i++) { lock_guard<mutex> lock(mtx); // automatically unlocks at scope end counter++; }}
thread t1(increment, 10000);thread t2(increment, 10000);t1.join(); t2.join();cout << counter; // 20000 (guaranteed correct)async and future
Section titled “async and future”std::async runs a function asynchronously and returns a future representing the result.
#include <future>
future<int> result = async(launch::async, []() { // expensive computation return 42;});
cout << result.get(); // blocks until ready, returns 42Thread-safe Summary
Section titled “Thread-safe Summary”| Primitive | Header | Purpose |
|---|---|---|
thread | <thread> | Run function in a new thread |
mutex | <mutex> | Mutual exclusion lock |
lock_guard<mutex> | <mutex> | RAII mutex lock |
unique_lock<mutex> | <mutex> | Flexible RAII lock (supports deferring, unlocking) |
condition_variable | <condition_variable> | Block thread until notified |
async | <future> | Launch async task |
future<T> | <future> | Retrieve result of async task |
atomic<T> | <atomic> | Lock-free thread-safe variable |
#include <atomic>atomic<int> counter{0};// safe to increment from multiple threads without a mutexcounter.fetch_add(1);RFC 959, Section Multithreading — "cppreference.com"
Command Line Arguments
Section titled “Command Line Arguments”int main(int argc, char* argv[]) { cout << "Program: " << argv[0] << endl; for (int i = 1; i < argc; i++) { cout << "Arg " << i << ": " << argv[i] << endl; } return 0;}argc is the argument count (including the program name). argv is an array of C-strings.
./app hello world# Arg 1: hello# Arg 2: worldRFC 959, Section Command Line Arguments — "cppreference.com"
File Handling
Section titled “File Handling”C++ performs file operations through the <fstream> library. Two primary classes handle file I/O: ofstream for writing to files and ifstream for reading from files.
#include <fstream>#include <iostream>#include <string>using namespace std;
int main() { // Writing to a file ofstream outputFile("example.txt"); if (outputFile.is_open()) { outputFile << "Hello, World!" << endl; outputFile << 42 << endl; outputFile.close(); }
// Reading from a file ifstream inputFile("example.txt"); if (inputFile.is_open()) { string line; while (getline(inputFile, line)) { cout << line << endl; } inputFile.close(); }
return 0;}Key file operations:
| Operation | Description |
|---|---|
open(filename) | Opens a file |
is_open() | Checks if the file was opened successfully |
close() | Closes the file |
getline(stream, str) | Reads a line into a string |
<< operator | Writes data to the file |
RFC 959, Section File Handling
Source & Further Reading
Section titled “Source & Further Reading”C++ Language Reference
A comprehensive reference combining cppreference.com, the ISO C++ standard, and community resources.