main() is the program entry point, returns int (0 = success).
#include <iostream> brings in the standard I/O stream library.
Comments
// Single line comment/* Multi-line comment *//// Doxygen-style doc comment (used for documentation generation)
Variables & Data Types
int age = 25; // Integer (4 bytes)float price = 9.99f; // Single precision float (4 bytes)double pi = 3.14159265; // Double precision float (8 bytes)char grade = 'A'; // Single character (1 byte)bool isActive = true; // Boolean (1 byte)std::string name = "Kiro"; // String (from <string>)// Constantsconst int MAX = 100;constexpr double TAX = 0.18; // Compile-time constant (C++11)
Primitive Data Types Table
Type Size Range
bool 1 byte true / false
char 1 byte -128 to 127
int 4 bytes -2,147,483,648 to 2,147,483,647
long 8 bytes -9.2E18 to 9.2E18
float 4 bytes ~6-7 decimal digits precision
double 8 bytes ~15-16 decimal digits precision
long double 10/16 bytes extended precision
wchar_t 2/4 bytes wide character
Type Modifiers
unsigned int u = 4294967295U; // no negative valuesshort int s = 32767; // 2 bytes (16 bits) , range -32,768 to 32,767long long ll = 9223372036854775807LL;unsigned long long ull = 18446744073709551615ULL;
auto & Type Deduction (C++11)
auto x = 42; // intauto y = 3.14; // doubleauto z = "hello"; // const char*auto s = std::string("hi"); // std::string// decltype — deduce type from expressionint a = 5;decltype(a) b = 10; // b is int
User Input
#include <iostream>#include <string>int main() { int num; std::string name; std::cout << "Enter a number: "; std::cin >> num; std::cout << "Enter your name: "; std::cin.ignore(); std::getline(std::cin, name); // reads full line with spaces std::cout << "Hello " << name << ", you entered " << num;}
// C-style (avoid in modern C++)double d = (double)5 / 2;// C++ style casts (preferred)int i = static_cast<int>(3.99); // 3 — safe compile-time castBase* b = new Derived();Derived* d = dynamic_cast<Derived*>(b); // safe runtime downcast (needs RTTI)const int ci = 5;int* p = const_cast<int*>(&ci); // removes const (use carefully)int* ip = reinterpret_cast<int*>(0xDEAD); // low-level bit reinterpretation
Control Flow
if / else if / else
int score = 85;if (score >= 90) { std::cout << "A";} else if (score >= 80) { std::cout << "B";} else if (score >= 70) { std::cout << "C";} else { std::cout << "F";}// Output: B
Switch Statement
int day = 3;switch (day) { case 1: std::cout << "Monday"; break; case 2: std::cout << "Tuesday"; break; case 3: std::cout << "Wednesday"; break; default: std::cout << "Other"; break;}
Ternary Operator
// condition ? if_true : if_falseint max = (a > b) ? a : b;std::string label = (age >= 18) ? "Adult" : "Minor";
Loops
// for loopfor (int i = 0; i < 5; i++) { std::cout << i << " ";}// Output: 0 1 2 3 4// while loopint i = 0;while (i < 5) { std::cout << i++;}// do-while (executes at least once)int n = 0;do { std::cout << n++;} while (n < 3);// range-based for (C++11)std::vector<int> nums = {1, 2, 3, 4, 5};for (int n : nums) { std::cout << n << " ";}// range-based with auto & reference (efficient for large objects)for (const auto& n : nums) { std::cout << n << " ";}
break / continue / goto
for (int i = 0; i < 10; i++) { if (i == 3) continue; // skip 3 if (i == 7) break; // stop at 7 std::cout << i << " ";}// Output: 0 1 2 4 5 6// goto (avoid in modern code, but valid)goto end;std::cout << "skipped";end:std::cout << "reached end";
Functions
Declaration, Definition & Calling
#include <iostream>int add(int a, int b); // declaration (prototype)int main() { std::cout << add(3, 4); // calling → 7}int add(int a, int b) { // definition return a + b;}
int area(int side) { return side * side; }int area(int w, int h) { return w * h; }double area(double r) { return 3.14159 * r * r; }std::cout << area(5); // 25std::cout << area(3, 4); // 12std::cout << area(2.0); // 12.566...
Pass by Value, Reference & Pointer
void byValue(int x) { x = 99; } // original unchangedvoid byRef(int& x) { x = 99; } // original changedvoid byPtr(int* x) { *x = 99; } // original changed via pointerint n = 5;byValue(n); // n = 5byRef(n); // n = 99byPtr(&n); // n = 99
Inline Functions
// Hint to compiler to expand function body at call site (avoids call overhead)inline int square(int x) { return x * x; }std::cout << square(5); // 25
Recursive Functions
int factorial(int n) { if (n <= 1) return 1; return n * factorial(n - 1);}std::cout << factorial(5); // 120
Lambda Functions (C++11)
// [capture](params) -> return_type { body }auto add = [](int a, int b) { return a + b; };std::cout << add(3, 4); // 7int x = 10;auto addX = [x](int n) { return n + x; }; // capture by valueauto addXRef = [&x](int n) { x += n; }; // capture by reference// capture all by value [=], all by ref [&]auto all = [=]() { return x * 2; };// used with STL algorithmsstd::vector<int> v = {3, 1, 4, 1, 5};std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });// v = {5, 4, 3, 1, 1}
std::function & Function Pointers
#include <functional>// Function pointerint (*fp)(int, int) = add;std::cout << fp(2, 3); // 5// std::function — wraps any callablestd::function<int(int, int)> fn = add;fn = [](int a, int b) { return a * b; };std::cout << fn(3, 4); // 12
Pointers & References
Pointers Basics
int val = 42;int* ptr = &val; // ptr holds address of valstd::cout << val; // 42 — valuestd::cout << &val; // 0x... — addressstd::cout << ptr; // 0x... — same addressstd::cout << *ptr; // 42 — dereference (value at address)*ptr = 99; // modifies val through pointerstd::cout << val; // 99
Pointer Arithmetic
int arr[] = {10, 20, 30, 40};int* p = arr;std::cout << *p; // 10std::cout << *(p+1); // 20std::cout << *(p+2); // 30p++; // move to next elementstd::cout << *p; // 20
Null Pointer & nullptr (C++11)
int* p = nullptr; // preferred over NULL or 0 in modern C++if (p != nullptr) { std::cout << *p;} else { std::cout << "null pointer";}
References
int a = 10;int& ref = a; // ref is an alias for aref = 20; // a is now 20std::cout << a; // 20// References vs Pointers:// - References cannot be null, pointers can// - References cannot be reassigned, pointers can// - References are safer and cleaner for most use cases
const Pointers
int x = 5, y = 10;const int* p1 = &x; // pointer to const — can't change *p1int* const p2 = &x; // const pointer — can't change p2 itselfconst int* const p3 = &x; // both const// p1 = &y; ✓ (can change where it points)// *p1 = 9; ✗ (can't change value)// p2 = &y; ✗ (can't change pointer)// *p2 = 9; ✓ (can change value)
Dynamic Memory (new / delete)
// Allocate single valueint* p = new int(42);std::cout << *p; // 42delete p; // free memoryp = nullptr; // good practice// Allocate arrayint* arr = new int[5]{1, 2, 3, 4, 5};std::cout << arr[2]; // 3delete[] arr; // must use delete[] for arrays// Prefer smart pointers over raw new/delete in modern C++
#include <array>std::array<int, 5> arr = {1, 2, 3, 4, 5};std::cout << arr[0]; // 1std::cout << arr.size(); // 5std::cout << arr.front(); // 1std::cout << arr.back(); // 5arr.fill(0); // set all to 0// iteratefor (const auto& x : arr) std::cout << x << " ";
std::string
#include <string>std::string s = "Hello, World!";std::cout << s.length(); // 13std::cout << s.size(); // 13 (same as length)std::cout << s[0]; // Hstd::cout << s.substr(7, 5); // Worldstd::cout << s.find("World"); // 7s += " C++"; // concatenations.replace(7, 5, "C++"); // replace "World" with "C++"s.erase(5, 2); // erase 2 chars at index 5// convertint n = std::stoi("42"); // string to intstd::string str = std::to_string(99); // int to string// compareif (s == "Hello") { ... }if (s.compare("Hello") == 0) { ... }// empty checkif (s.empty()) { ... }
String Views (C++17) — Zero-copy string reference
#include <string_view>void print(std::string_view sv) { std::cout << sv; // no copy made}std::string s = "Hello";print(s); // works with std::stringprint("World"); // works with string literals
OOP — Object-Oriented Programming
Classes & Objects
class Car {public: std::string brand; int year; void display() { std::cout << brand << " (" << year << ")\n"; }};Car c;c.brand = "Toyota";c.year = 2022;c.display(); // Toyota (2022)
Constructors & Destructors
class Person {public: std::string name; int age; // Default constructor Person() : name("Unknown"), age(0) {} // Parameterized constructor Person(std::string n, int a) : name(n), age(a) {} // Copy constructor Person(const Person& other) : name(other.name), age(other.age) {} // Destructor ~Person() { std::cout << name << " destroyed\n"; } void show() { std::cout << name << ", " << age << "\n"; }};Person p1("Alice", 30);Person p2 = p1; // copy constructorp1.show(); // Alice, 30
Access Modifiers
class BankAccount {public: std::string owner; // accessible everywhereprotected: double balance; // accessible in class + subclassesprivate: std::string pin; // accessible only inside this class};
Getters & Setters (Encapsulation)
class Temperature {private: double celsius;public: void setCelsius(double c) { if (c >= -273.15) celsius = c; } double getCelsius() const { return celsius; } double getFahrenheit() const { return celsius * 9.0/5.0 + 32; }};Temperature t;t.setCelsius(100);std::cout << t.getFahrenheit(); // 212
Static Members
class Counter {public: static int count; // shared across all instances Counter() { count++; } ~Counter() { count--; } static int getCount() { return count; } // static method};int Counter::count = 0; // must define outside classCounter a, b, c;std::cout << Counter::getCount(); // 3
Friend Functions & Classes
class Box {private: double width;public: Box(double w) : width(w) {} friend double getWidth(Box b); // friend function declaration};double getWidth(Box b) { return b.width; // can access private member}Box b(5.5);std::cout << getWidth(b); // 5.5
class Animal {public: std::string name; Animal(std::string n) : name(n) {} void eat() { std::cout << name << " is eating\n"; }};class Dog : public Animal {public: Dog(std::string n) : Animal(n) {} void bark() { std::cout << name << " says Woof!\n"; }};Dog d("Rex");d.eat(); // Rex is eatingd.bark(); // Rex says Woof!
Inheritance Types
class Base { ... };class PublicDerived : public Base { ... }; // public → public, protected → protectedclass ProtectedDerived : protected Base { ... }; // public → protectedclass PrivateDerived : private Base { ... }; // all → private
Multi-Level & Multiple Inheritance
// Multi-levelclass A { public: void hello() { std::cout << "A\n"; } };class B : public A {};class C : public B {}; // C inherits from B which inherits from AC obj;obj.hello(); // A// Multiple inheritanceclass Flyable { public: void fly() { std::cout << "Flying\n"; } };class Swimmable { public: void swim() { std::cout << "Swimming\n"; } };class Duck : public Flyable, public Swimmable {};Duck d;d.fly(); // Flyingd.swim(); // Swimming
Virtual Inheritance (Diamond Problem Fix)
class A { public: int x = 1; };class B : virtual public A {};class C : virtual public A {};class D : public B, public C {}; // only one copy of AD obj;std::cout << obj.x; // 1 — no ambiguity
Constructor Chaining
class Shape {public: std::string color; Shape(std::string c) : color(c) { std::cout << "Shape created\n"; }};class Circle : public Shape {public: double radius; Circle(std::string c, double r) : Shape(c), radius(r) { std::cout << "Circle created\n"; }};Circle ci("red", 5.0);// Output:// Shape created// Circle created
class Animal {public: virtual void sound() = 0; // pure virtual — makes class abstract virtual ~Animal() {}};// Animal a; // ERROR — cannot instantiate abstract classclass Dog : public Animal {public: void sound() override { std::cout << "Woof!\n"; }};class Cat : public Animal {public: void sound() override { std::cout << "Meow!\n"; }};Animal* a = new Dog();a->sound(); // Woof!delete a;
override & final (C++11)
class Base {public: virtual void foo() {} virtual void bar() {}};class Derived : public Base {public: void foo() override {} // override — compiler checks it actually overrides void bar() override final {} // final — no further override allowed};class Leaf : public Derived { // void bar() override {} // ERROR — bar is final};
vtable & vptr (How Virtual Works Internally)
Each class with virtual functions has a vtable (virtual function table).
Each object has a hidden vptr pointing to its class’s vtable.
At runtime, the correct function is looked up via the vtable — this is dynamic dispatch.
// Conceptually:// Circle vtable → { &Circle::area, &Circle::draw }// Rectangle vtable → { &Rectangle::area, &Rectangle::draw }Shape* s = new Circle(3);s->area(); // looks up Circle::area via vptr → vtable
OOP — Advanced Concepts
Rule of Three / Five / Zero
// Rule of Three: if you define any of these, define all three:// destructor, copy constructor, copy assignment operator// Rule of Five (C++11): also define move constructor & move assignmentclass Buffer { int* data; size_t size;public: Buffer(size_t s) : size(s), data(new int[s]) {} ~Buffer() { delete[] data; } // destructor Buffer(const Buffer& o) : size(o.size), data(new int[o.size]) { std::copy(o.data, o.data + size, data); // copy constructor } Buffer& operator=(const Buffer& o) { // copy assignment if (this != &o) { delete[] data; size = o.size; data = new int[size]; std::copy(o.data, o.data + size, data); } return *this; } Buffer(Buffer&& o) noexcept : size(o.size), data(o.data) { // move constructor o.data = nullptr; o.size = 0; } Buffer& operator=(Buffer&& o) noexcept { // move assignment if (this != &o) { delete[] data; data = o.data; size = o.size; o.data = nullptr; o.size = 0; } return *this; }};// Rule of Zero: use smart pointers/STL — no manual resource management needed
Move Semantics & rvalue References (C++11)
std::string a = "Hello";std::string b = std::move(a); // moves a's data into b — no copy// a is now in valid but unspecified state// rvalue reference: T&&void process(std::string&& s) { std::cout << "moved: " << s;}process(std::move(b));// std::move doesn't move — it casts to rvalue reference// actual move happens in move constructor/assignment
RAII (Resource Acquisition Is Initialization)
// Core C++ idiom: tie resource lifetime to object lifetime// Resource acquired in constructor, released in destructorclass FileHandle { FILE* file;public: FileHandle(const char* path) { file = fopen(path, "r"); if (!file) throw std::runtime_error("Cannot open file"); } ~FileHandle() { if (file) fclose(file); // always released, even on exception } FILE* get() { return file; }};{ FileHandle f("data.txt"); // acquired // use f.get()...} // destructor called here — file closed automatically
Smart Pointers (C++11)
unique_ptr — Exclusive Ownership
#include <memory>std::unique_ptr<int> p = std::make_unique<int>(42);std::cout << *p; // 42// cannot copy, only movestd::unique_ptr<int> p2 = std::move(p);// p is now nullptr// with custom classauto obj = std::make_unique<Person>("Alice", 30);obj->show();// automatically deleted when out of scope — no delete needed
shared_ptr — Shared Ownership
auto sp1 = std::make_shared<int>(100);auto sp2 = sp1; // both own the resourcestd::cout << sp1.use_count(); // 2 — reference countstd::cout << *sp1; // 100sp1.reset(); // sp1 releases ownershipstd::cout << sp2.use_count(); // 1// resource deleted when last shared_ptr goes out of scope
Type Ownership Copyable Use Case
unique_ptr Exclusive No Single owner, factory returns
shared_ptr Shared (ref cnt) Yes Multiple owners, shared data
weak_ptr None (observer) Yes Break cycles, cache, observer
Templates & Generic Programming
Function Templates
template <typename T>T maxOf(T a, T b) { return (a > b) ? a : b;}std::cout << maxOf(3, 7); // 7 (int)std::cout << maxOf(3.5, 2.1); // 3.5 (double)std::cout << maxOf('a', 'z'); // z (char)// Multiple type paramstemplate <typename T, typename U>auto add(T a, U b) -> decltype(a + b) { return a + b;}
class AppError : public std::exception { std::string msg;public: AppError(std::string m) : msg(m) {} const char* what() const noexcept override { return msg.c_str(); }};throw AppError("Something went wrong");
noexcept (C++11)
void safeFunc() noexcept { // guarantees no exception is thrown // if one is thrown, std::terminate() is called}// noexcept is important for move constructors — enables optimizationsBuffer(Buffer&& o) noexcept { ... }
Modern C++ Features
C++11 Key Features
// auto type deductionauto x = 42;// Range-based forfor (const auto& item : container) { ... }// nullptrint* p = nullptr;// Lambda expressionsauto fn = [](int x) { return x * 2; };// Smart pointersauto sp = std::make_shared<MyClass>();// Move semanticsstd::string s = std::move(other);// Initializer listsstd::vector<int> v = {1, 2, 3, 4, 5};// constexprconstexpr int SIZE = 256;// static_assertstatic_assert(sizeof(int) == 4, "int must be 4 bytes");// Delegating constructorsclass Foo { Foo(int x) : Foo(x, 0) {} Foo(int x, int y) { ... }};// override & finalvoid foo() override final {}// Scoped enumsenum class Color { Red, Green, Blue };Color c = Color::Red;
C++14 Key Features
// Generic lambdasauto add = [](auto a, auto b) { return a + b; };// Return type deductionauto square(int x) { return x * x; }// std::make_uniqueauto p = std::make_unique<int>(42);// Binary literals & digit separatorsint flags = 0b1010'1010;long big = 1'000'000;
C++17 Key Features
// Structured bindingsauto [x, y] = std::pair{1, 2};for (auto& [key, val] : myMap) { ... }// if constexpr — compile-time branchingtemplate <typename T>void process(T val) { if constexpr (std::is_integral_v<T>) { std::cout << "integer: " << val; } else { std::cout << "other: " << val; }}// std::optional — value that may or may not exist#include <optional>std::optional<int> findValue(bool found) { if (found) return 42; return std::nullopt;}auto val = findValue(true);if (val) std::cout << *val; // 42// std::variant — type-safe union#include <variant>std::variant<int, double, std::string> v = "hello";std::cout << std::get<std::string>(v);// std::any — holds any type#include <any>std::any a = 42;a = std::string("hello");std::cout << std::any_cast<std::string>(a);// Filesystem#include <filesystem>namespace fs = std::filesystem;fs::create_directory("mydir");for (auto& entry : fs::directory_iterator(".")) { std::cout << entry.path() << "\n";}// Parallel algorithms#include <execution>std::sort(std::execution::par, v.begin(), v.end());
C++20 Key Features
// Concepts (see Templates section)template <std::integral T>T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }// Ranges — composable, lazy algorithms#include <ranges>auto v = std::vector{1,2,3,4,5,6,7,8,9,10};auto result = v | std::views::filter([](int x){ return x % 2 == 0; }) | std::views::transform([](int x){ return x * x; });for (int x : result) std::cout << x << " "; // 4 16 36 64 100// Coroutines (co_await, co_yield, co_return)#include <coroutine>// Used for async code, generators, lazy sequences// std::span — non-owning view over contiguous data#include <span>void process(std::span<int> data) { for (int x : data) std::cout << x;}int arr[] = {1,2,3};process(arr);// Three-way comparison operator <=>auto result = (5 <=> 3); // std::strong_ordering::greater// Modules (replaces #include for large projects)// import std; // import entire standard library (compiler support varies)// consteval — must be evaluated at compile timeconsteval int square(int x) { return x * x; }constexpr int s = square(5); // 25
C++23 Highlights
// std::print / std::println (finally!)#include <print>std::println("Hello, {}!", "World");std::print("x = {}, y = {}\n", 1, 2);// std::expected — error handling without exceptions#include <expected>std::expected<int, std::string> divide(int a, int b) { if (b == 0) return std::unexpected("division by zero"); return a / b;}auto r = divide(10, 2);if (r) std::cout << *r;else std::cout << r.error();// std::flat_map / std::flat_set — cache-friendly sorted containers// Deducing this (explicit object parameter)struct Widget { auto& value(this auto& self) { return self.val; } int val;};
Concurrency & Multithreading
std::thread (C++11)
#include <thread>#include <iostream>void task(int id) { std::cout << "Thread " << id << " running\n";}int main() { std::thread t1(task, 1); std::thread t2(task, 2); t1.join(); // wait for t1 to finish t2.join(); // wait for t2 to finish // t.detach() — run independently (fire and forget)}
#include <future>int compute(int x) { return x * x; }// Launch async taskstd::future<int> f = std::async(std::launch::async, compute, 5);// Do other work...int result = f.get(); // blocks until result is readystd::cout << result; // 25// std::promise — manually set a future valuestd::promise<int> p;std::future<int> fut = p.get_future();std::thread t([&p]{ p.set_value(42); });std::cout << fut.get(); // 42t.join();
Atomic Operations (C++11)
#include <atomic>std::atomic<int> counter{0};void increment() { counter++; // atomic — thread-safe, no mutex needed counter.fetch_add(1); // explicit atomic add}std::cout << counter.load(); // atomic readcounter.store(0); // atomic write// Compare-and-swapint expected = 5;counter.compare_exchange_strong(expected, 10);// if counter == 5, set to 10; else load current into expected
File I/O
Reading & Writing Files
#include <fstream>#include <string>// Write to filestd::ofstream outFile("data.txt");if (outFile.is_open()) { outFile << "Hello, File!\n"; outFile << "Line 2\n"; outFile.close();}// Read from filestd::ifstream inFile("data.txt");std::string line;while (std::getline(inFile, line)) { std::cout << line << "\n";}inFile.close();// Append to filestd::ofstream appendFile("data.txt", std::ios::app);appendFile << "Appended line\n";
// Limits visibility to current translation unit (like static in C)namespace { int internalHelper() { return 42; }}// internalHelper() only accessible in this .cpp file
Preprocessor & Compilation
Preprocessor Directives
#include <iostream> // system header#include "myfile.h" // local header#define PI 3.14159#define MAX(a,b) ((a) > (b) ? (a) : (b))#undef PI#ifdef DEBUG std::cout << "Debug mode\n";#elif defined VERBOSE std::cout << "Verbose mode\n";#else std::cout << "Release mode\n";#endif#ifndef MYHEADER_H#define MYHEADER_H// header content#endif#pragma once // modern alternative to include guards#error "Unsupported platform" // compile-time error
Predefined Macros
__FILE__ // current filename__LINE__ // current line number__DATE__ // compilation date "MMM DD YYYY"__TIME__ // compilation time "HH:MM:SS"__cplusplus // C++ standard version (201703L = C++17, 202002L = C++20)__func__ // current function name (C++11)
// Substitution Failure Is Not An Error// Enable function only for integral typestemplate <typename T>typename std::enable_if_t<std::is_integral_v<T>, T>double_it(T x) { return x * 2; }double_it(5); // works// double_it(3.14); // compile error — not integral// C++20 Concepts are cleaner — prefer those
constexpr & Compile-Time Programming
constexpr int factorial(int n) { return n <= 1 ? 1 : n * factorial(n - 1);}constexpr int f5 = factorial(5); // computed at compile time: 120// constexpr if (C++17)template <typename T>auto process(T val) { if constexpr (std::is_integral_v<T>) return val * 2; else return val + 0.5;}// consteval (C++20) — MUST be compile-timeconsteval int square(int x) { return x * x; }
Memory Model & Alignment
// alignas — specify alignmentalignas(16) float simdData[4]; // 16-byte aligned for SIMD// alignof — query alignmentstd::cout << alignof(double); // typically 8// std::aligned_storage (C++11)std::aligned_storage_t<sizeof(int), alignof(int)> storage;// Placement new — construct in pre-allocated memorychar buf[sizeof(MyClass)];MyClass* obj = new (buf) MyClass(); // construct in bufobj->~MyClass(); // must manually call destructor
int global = 10; // global scope — accessible everywhere in filevoid foo() { int local = 5; // local scope — only inside foo() { int block = 3; // block scope — only inside this {} std::cout << local + block; // 8 } // block is destroyed here}// Shadowing — inner variable hides outerint x = 1;{ int x = 2; // shadows outer x std::cout << x; // 2}std::cout << x; // 1
Storage Duration
// Automatic — default for local variables, destroyed at end of scopevoid foo() { int x = 5; } // x destroyed when foo() returns// Static — persists for program lifetimevoid counter() { static int count = 0; // initialized once, persists between calls count++; std::cout << count;}counter(); // 1counter(); // 2counter(); // 3// Dynamic — heap, controlled by new/delete or smart pointersint* p = new int(42);delete p;// Thread-local (C++11) — one copy per threadthread_local int tls = 0;
Linkage (extern, static)
// External linkage — visible across translation unitsint globalVar = 42; // external by defaultextern int globalVar; // declare in other .cpp files// Internal linkage — visible only in current translation unitstatic int fileLocal = 10; // static at file scope = internal linkagenamespace { int anon = 5; } // anonymous namespace = internal linkage// inline variables (C++17) — define in header, one definition across TUsinline int sharedConst = 100;// constinit (C++20) — guarantee static init at compile timeconstinit int initAtCompileTime = 42;
Bit Manipulation
Bitwise Operations
int a = 0b1010; // 10int b = 0b1100; // 12std::cout << (a & b); // AND → 0b1000 = 8std::cout << (a | b); // OR → 0b1110 = 14std::cout << (a ^ b); // XOR → 0b0110 = 6std::cout << (~a); // NOT → -11 (two's complement)std::cout << (a << 1); // LEFT SHIFT → 0b10100 = 20std::cout << (a >> 1); // RIGHT SHIFT → 0b0101 = 5
Common Bit Tricks
int n = 42;// Check if bit i is setbool isSet = (n >> i) & 1;// Set bit in |= (1 << i);// Clear bit in &= ~(1 << i);// Toggle bit in ^= (1 << i);// Check if power of 2bool isPow2 = n > 0 && (n & (n - 1)) == 0;// Count set bits (popcount)int bits = __builtin_popcount(n); // GCC/Clangint bits2 = std::popcount((unsigned)n); // C++20 <bit>// Isolate lowest set bitint lowest = n & (-n);// Clear lowest set bitn = n & (n - 1);// Swap without tempa ^= b; b ^= a; a ^= b;
std::bitset
#include <bitset>std::bitset<8> bits(0b10110100); // 8-bit setstd::cout << bits; // 10110100std::cout << bits[3]; // 0 (bit at position 3)std::cout << bits.count(); // 4 (number of set bits)std::cout << bits.size(); // 8bits.set(0); // set bit 0 → 10110101bits.reset(7); // clear bit 7 → 00110101bits.flip(1); // toggle bit 1bits.flip(); // flip all bitsstd::cout << bits.to_ulong(); // convert to unsigned longstd::cout << bits.to_string(); // convert to string// Bitwise ops on bitsetsstd::bitset<8> a(0b1010), b(0b1100);std::cout << (a & b); // 00001000std::cout << (a | b); // 00001110std::cout << (a ^ b); // 00000110
// Old-style enum (pollutes namespace)enum Direction { North, South, East, West };Direction d = North;// Scoped enum (C++11) — preferredenum class Color { Red, Green, Blue };Color c = Color::Red;// Enum with underlying typeenum class Status : uint8_t { OK = 0, Error = 1, Pending = 2 };// Cast to underlying typeint val = static_cast<int>(Color::Green); // 1
Unions & std::variant
// C-style union — unsafe, no type trackingunion Data { int i; float f; char c;};Data d; d.i = 42;// std::variant (C++17) — type-safe unionstd::variant<int, float, std::string> v = 42;v = 3.14f;v = "hello";std::visit([](auto&& val) { std::cout << val; }, v);
Escape Sequences
\n Newline\t Horizontal tab\r Carriage return\\ Backslash\' Single quote\" Double quote\0 Null character\a Bell/alert\b Backspace\f Form feed\v Vertical tab\xNN Hex value (e.g. \x41 = 'A')\uNNNN Unicode (C++11)
// Integer literalsint dec = 255; // decimalint hex = 0xFF; // hexadecimalint oct = 0377; // octalint bin = 0b11111111; // binary (C++14)// Digit separators (C++14)int million = 1'000'000;double pi = 3.141'592'653;// Type suffixesauto a = 42; // intauto b = 42u; // unsigned intauto c = 42l; // longauto d = 42ll; // long longauto e = 42ul; // unsigned longauto f = 3.14f; // floatauto g = 3.14; // doubleauto h = 3.14l; // long double// String literalsconst char* s1 = "hello";const wchar_t* s2 = L"wide";const char16_t* s3 = u"utf16";const char32_t* s4 = U"utf32";const char* s5 = u8"utf8";// Raw string literals (no escape processing)const char* path = R"(C:\Users\name\file.txt)";const char* regex = R"(\d+\.\d+)";// User-defined literals (C++11)// operator"" suffixlong double operator"" _km(long double d) { return d * 1000.0; }long double dist = 5.0_km; // 5000.0
Type Aliases
// Old C-style typedeftypedef unsigned long long uint64;typedef std::vector<int> IntVec;// Modern using alias (C++11) — preferredusing uint64 = unsigned long long;using IntVec = std::vector<int>;using StringMap = std::map<std::string, std::string>;// Alias templates — typedef can't do thistemplate <typename T>using Vec = std::vector<T>;Vec<int> vi = {1, 2, 3};Vec<std::string> vs = {"a", "b"};// Function pointer aliasusing Callback = void(*)(int, int);using Handler = std::function<void(std::string)>;
Character Manipulation (<cctype>)
#include <cctype>#include <string>#include <algorithm>char c = 'A';// Classificationstd::isalpha(c); // true — is letterstd::isdigit(c); // false — is digitstd::isalnum(c); // true — is letter or digitstd::isspace(c); // false — is whitespacestd::isupper(c); // true — is uppercasestd::islower(c); // false — is lowercasestd::ispunct(c); // false — is punctuation// Conversionstd::tolower('A'); // 'a'std::toupper('a'); // 'A'// Convert entire stringstd::string s = "Hello World";std::transform(s.begin(), s.end(), s.begin(), ::tolower);// s = "hello world"std::transform(s.begin(), s.end(), s.begin(), ::toupper);// s = "HELLO WORLD"// Count digits in stringint digits = std::count_if(s.begin(), s.end(), ::isdigit);
Arguments to main & Getting Things Out of Functions
argc & argv
// int main(int argc, char* argv[])// argc — argument count (includes program name)// argv — array of C-stringsint main(int argc, char* argv[]) { std::cout << "Program: " << argv[0] << "\n"; std::cout << "Args: " << argc - 1 << "\n"; for (int i = 1; i < argc; i++) { std::cout << "arg[" << i << "] = " << argv[i] << "\n"; } return 0;}// Run: ./app hello world 42// Program: ./app// Args: 3// arg[1] = hello// arg[2] = world// arg[3] = 42// Convert argsint n = std::stoi(argv[1]);double d = std::stod(argv[2]);
Multiple Return Strategies
// 1. Return structstruct MinMax { int min, max; };MinMax getMinMax(std::vector<int>& v) { return { *std::min_element(v.begin(), v.end()), *std::max_element(v.begin(), v.end()) };}auto [mn, mx] = getMinMax(v); // structured binding// 2. Return std::pairstd::pair<bool, int> findFirst(std::vector<int>& v, int target) { for (int i = 0; i < v.size(); i++) if (v[i] == target) return {true, i}; return {false, -1};}auto [found, idx] = findFirst(v, 3);// 3. Return std::tuplestd::tuple<int, int, int> divide(int a, int b) { return {a / b, a % b, b};}auto [quot, rem, divisor] = divide(17, 5);// 4. Return std::optional (value or nothing)std::optional<int> safeSqrt(int n) { if (n < 0) return std::nullopt; return static_cast<int>(std::sqrt(n));}if (auto r = safeSqrt(16)) std::cout << *r; // 4// 5. Output parameters (old style, avoid when possible)void getCoords(int& x, int& y) { x = 10; y = 20; }int x, y; getCoords(x, y);
Overflow, Underflow & Numeric Limits
Integer Overflow & Underflow
#include <climits>#include <limits>// Numeric limitsstd::cout << INT_MAX; // 2147483647std::cout << INT_MIN; // -2147483648std::cout << UINT_MAX; // 4294967295std::cout << LLONG_MAX; // 9223372036854775807// std::numeric_limits (preferred, works for any type)std::cout << std::numeric_limits<int>::max();std::cout << std::numeric_limits<int>::min();std::cout << std::numeric_limits<double>::max();std::cout << std::numeric_limits<double>::epsilon(); // smallest diffstd::cout << std::numeric_limits<float>::infinity();// Overflow wraps around for unsigned (defined behavior)unsigned int u = UINT_MAX;u++; // u = 0 (wraps)// Overflow for signed int is UNDEFINED BEHAVIORint i = INT_MAX;i++; // UB — don't do this// Safe check before overflowif (a > std::numeric_limits<int>::max() - b) { // would overflow}
Floating Point Precision
// Floating point is not exactdouble a = 0.1 + 0.2;std::cout << (a == 0.3); // 0 (false!) — precision issue// Correct comparisondouble epsilon = 1e-9;std::cout << (std::abs(a - 0.3) < epsilon); // 1 (true)// Special valuesdouble inf = std::numeric_limits<double>::infinity();double nan = std::numeric_limits<double>::quiet_NaN();std::cout << std::isinf(inf); // 1std::cout << std::isnan(nan); // 1std::cout << std::isfinite(42.0); // 1
Deep Dive: Classes & Constructors
Class Memory Layout & this Pointer
class Point {public: int x, y; Point(int x, int y) : x(x), y(y) {} void print() { // 'this' is a pointer to the current object std::cout << this->x << ", " << this->y; std::cout << " (at " << this << ")\n"; } // Return *this for method chaining Point& setX(int x) { this->x = x; return *this; } Point& setY(int y) { this->y = y; return *this; }};Point p(1, 2);p.setX(10).setY(20); // method chaining// sizeof classstd::cout << sizeof(Point); // 8 (two ints, no padding needed)// Memory layout: members stored in declaration order// Padding added for alignmentstruct Padded { char a; int b; char c; };std::cout << sizeof(Padded); // likely 12, not 6 (padding)struct Packed { int b; char a; char c; };std::cout << sizeof(Packed); // likely 8 (better layout)
Constructor Details
class Widget { int id; std::string name; double value;public: // Member initializer list — always prefer over assignment in body // Initialized in DECLARATION ORDER, not list order Widget(int i, std::string n, double v) : id(i), name(std::move(n)), value(v) {} // Delegating constructor (C++11) — one constructor calls another Widget() : Widget(0, "default", 0.0) {} Widget(int i) : Widget(i, "unnamed", 0.0) {} // Converting constructor — implicit conversion from int Widget(int i) : id(i), name(""), value(0) {} // explicit — prevents implicit conversion explicit Widget(double v) : id(0), name(""), value(v) {}};Widget w1(1, "hello", 3.14);Widget w2; // calls delegating constructorWidget w3 = 42; // implicit conversion (if not explicit)// Widget w4 = 3.14; // ERROR if constructor is explicitWidget w4(3.14); // OK — explicit call// = delete — disable a constructorclass NonCopyable {public: NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; // no copy NonCopyable& operator=(const NonCopyable&) = delete;};// = default — compiler generates default implementationclass Simple {public: Simple() = default; ~Simple() = default;};
Three-Way Comparison & Logical Operators
Three-Way Comparison <=> (C++20)
#include <compare>// Returns ordering type, not boolauto r1 = (5 <=> 3); // std::strong_ordering::greaterauto r2 = (3 <=> 5); // std::strong_ordering::lessauto r3 = (5 <=> 5); // std::strong_ordering::equal// Ordering types:// strong_ordering — for integers (equal means identical)// weak_ordering — for floats (equivalent but not identical)// partial_ordering — for floats with NaN (incomparable possible)// Check resultif (r1 > 0) std::cout << "greater";if (r1 < 0) std::cout << "less";if (r1 == 0) std::cout << "equal";// Auto-generate all comparison operators from <=>struct Point { int x, y; auto operator<=>(const Point&) const = default; // Now ==, !=, <, >, <=, >= all work automatically};Point a{1, 2}, b{1, 3};std::cout << (a < b); // truestd::cout << (a == b); // false// Custom spaceship operatorstruct Version { int major, minor, patch; std::strong_ordering operator<=>(const Version& o) const { if (auto c = major <=> o.major; c != 0) return c; if (auto c = minor <=> o.minor; c != 0) return c; return patch <=> o.patch; } bool operator==(const Version&) const = default;};
Short-Circuit Evaluation
// && stops at first false// || stops at first trueint x = 0;if (x != 0 && 10 / x > 1) { // safe — 10/x never evaluated if x==0 std::cout << "ok";}// Useful for null checksstd::string* p = nullptr;if (p != nullptr && p->length() > 0) { // safe std::cout << *p;}// Side effects in conditions (avoid, but know it exists)int a = 0, b = 0;if (++a || ++b) { // b is never incremented std::cout << a << " " << b; // 1 0}
Function-Like Entities
Functors (Function Objects)
// A class with operator() — behaves like a function but has stateclass Multiplier { int factor;public: Multiplier(int f) : factor(f) {} int operator()(int x) const { return x * factor; }};Multiplier triple(3);std::cout << triple(5); // 15std::cout << triple(10); // 30// Used with STL algorithmsstd::vector<int> v = {1, 2, 3, 4, 5};std::transform(v.begin(), v.end(), v.begin(), Multiplier(2));// v = {2, 4, 6, 8, 10}
std::bind (C++11)
#include <functional>int add(int a, int b) { return a + b; }// Bind first argument to 10auto add10 = std::bind(add, 10, std::placeholders::_1);std::cout << add10(5); // 15std::cout << add10(20); // 30// Bind member functionclass Printer {public: void print(std::string msg) { std::cout << msg; }};Printer p;auto fn = std::bind(&Printer::print, &p, std::placeholders::_1);fn("Hello"); // Hello// Note: prefer lambdas over std::bind in modern C++auto add10_lambda = [](int x) { return add(10, x); };
std::invoke (C++17)
#include <functional>// Uniformly call any callable: function, lambda, functor, member fnint add(int a, int b) { return a + b; }std::invoke(add, 3, 4); // 7 — free functionstd::invoke([](int x){ return x*2; }, 5); // 10 — lambdastruct Foo { int val; int get() { return val; } };Foo f{42};std::invoke(&Foo::get, f); // 42 — member functionstd::invoke(&Foo::val, f); // 42 — member variable
Ranges Library (C++20)
Views & Pipelines
#include <ranges>#include <vector>std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};// filter — keep only even numbersauto evens = v | std::views::filter([](int x){ return x % 2 == 0; });// transform — square eachauto squared = evens | std::views::transform([](int x){ return x * x; });// Chain (lazy — nothing computed until iterated)for (int x : squared) std::cout << x << " "; // 4 16 36 64 100// take / dropauto first3 = v | std::views::take(3); // {1, 2, 3}auto skip2 = v | std::views::drop(2); // {3, 4, 5, ...}// reverseauto rev = v | std::views::reverse;// iota — generate sequencefor (int i : std::views::iota(1, 6)) std::cout << i; // 12345// keys / values (for maps)std::map<std::string, int> m{{"a",1},{"b",2}};for (auto& k : m | std::views::keys) std::cout << k; // abfor (auto& v : m | std::views::values) std::cout << v; // 12
Range Algorithms
#include <algorithm>#include <ranges>std::vector<int> v = {5, 3, 1, 4, 2};// Ranges versions — no begin/end neededstd::ranges::sort(v); // {1,2,3,4,5}std::ranges::reverse(v); // {5,4,3,2,1}auto it = std::ranges::find(v, 3);bool found = std::ranges::contains(v, 3); // C++23std::ranges::sort(v, std::greater{}); // descendingstd::ranges::sort(v, {}, &MyStruct::key); // sort by member// Projections — transform before comparingstruct Person { std::string name; int age; };std::vector<Person> people = {{"Bob",30},{"Alice",25}};std::ranges::sort(people, {}, &Person::age); // sort by agestd::ranges::sort(people, {}, &Person::name); // sort by name
Coroutines (C++20)
Coroutine Basics
A coroutine is a function that can suspend and resume execution.
Uses three keywords: co_await, co_yield, co_return
Requires a promise type and a coroutine handle — usually provided by a library.
// co_await suspends the coroutine until the awaitable completes// Used for async I/O, networking, task scheduling// Conceptual async task (real impl needs a scheduler/runtime)Task<int> fetchData() { auto result = co_await asyncHttpGet("https://api.example.com"); co_return result.statusCode;}// std::suspend_always — always suspends// std::suspend_never — never suspends (runs to completion)// In practice, use a library:// - cppcoro (popular coroutine library)// - Asio (networking with coroutines)// - C++23 std::generator for simple generators
Modules (C++20)
Module Basics
Modules replace #include — faster compilation, no header guards, no macro leakage.
// math.ixx (or math.cppm) — module interface unitexport module math; // declare moduleexport int add(int a, int b) { return a + b; } // exported — visible to importersint helper() { return 42; } // NOT exported — internal onlyexport namespace Math { double pi = 3.14159; double square(double x) { return x * x; }}