A language tour
Zero-cost abstractions. The belief that you should pay only for what you use — in performance and in complexity.
01 — Zero-Cost Abstractions
Bjarne Stroustrup's guiding principle: abstractions should cost nothing if you don't use them, and no more than hand-written code if you do. C++ proves this is achievable — high-level code that compiles to tight machine instructions.
"C++ is designed to allow you to express ideas, and if you don't know the ideas you want to express, C++ isn't going to help you much."
— Bjarne Stroustrup#include <algorithm> #include <vector> #include <numeric> int main() { std::vector<int> v = { 3, 1, 4, 1, 5, 9, 2, 6 }; // This range-based for loop compiles identically to a raw index loop int total = 0; for (const auto& x : v) total += x; // Lambda + algorithm — no virtual dispatch, inlined at compile time std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; }); // Same performance as hand-written quicksort on ints return 0; }
The lambda passed to std::sort is not a pointer — it's an inlined callable. The compiler erases the abstraction entirely, generating the same code as if you wrote the comparison inline.
02 — Templates
C++ templates generate specialised code for each type at compile time. No boxing, no virtual dispatch, no type erasure overhead — the abstraction dissolves into optimised machine code before it ever runs.
template <typename T> T clamp(T val, T lo, T hi) { return val < lo ? lo : (val > hi ? hi : val); } // Concept constraint (C++20) — only accept arithmetic types template <typename T> requires std::is_arithmetic_v<T> T lerp(T a, T b, float t) { return a + (b - a) * t; } int main() { auto fi = clamp(15, 0, 10); // int version auto fd = clamp(0.7, 0.0, 1.0); // double version auto mid = lerp(0.0f, 100.0f, 0.5f); // → 50.0 return 0; }
The compiler instantiates a separate clamp<int> and clamp<double> — two specialised functions, each as fast as hand-written code for that type.
03 — RAII
Resource Acquisition Is Initialization is C++'s answer to manual memory management. Constructors acquire resources; destructors release them. When an object goes out of scope, cleanup happens automatically — no garbage collector required.
#include <fstream> #include <memory> #include <string> struct DatabaseConnection { DatabaseConnection(const std::string& url) { /* connect */ } ~DatabaseConnection() { /* disconnect automatically */ } }; void process_data() { // File closes automatically at end of scope std::ifstream file("data.txt"); // Memory freed automatically — no delete needed auto conn = std::make_unique<DatabaseConnection>("postgres://localhost"); // Even if an exception is thrown here, both are cleaned up throw std::runtime_error("something went wrong"); // conn.~unique_ptr() and file.~ifstream() run here — guaranteed }
RAII makes exception safety tractable. Resources clean themselves up when their owner's lifetime ends — no finally blocks, no leak paths, no manual bookkeeping.
04 — Move Semantics
Modern C++ distinguishes between copying data and moving ownership. Move semantics let you transfer the guts of an object — its heap allocation, its file handle — without the cost of duplication. It changed how idiomatic C++ is written.
#include <string> #include <vector> #include <utility> int main() { std::string a = "Hello, long string that lives on the heap"; // Copy: allocates new memory, duplicates contents std::string b = a; // a still valid, b is a full copy // Move: steals the heap buffer — O(1) regardless of string length std::string c = std::move(a); // a is now empty, c owns the buffer // Returning a local: automatically moved, not copied auto make_big_vector = []() -> std::vector<int> { std::vector<int> v(1'000'000); return v; // RVO or move — no million-element copy }; return 0; }
The apostrophe in 1'000'000 is a C++14 digit separator — a small readability feature that lets you write large literals the way humans write them.
05 — Lambdas & Ranges
C++20's ranges library brings pipeline-style composition to C++ without virtual dispatch or heap allocation. Combined with lambdas, it lets you express complex transformations with the clarity of a functional language and the performance of C.
#include <ranges> #include <vector> #include <print> int main() { std::vector<int> nums = { 1,2,3,4,5,6,7,8,9,10 }; // Lazy pipeline — nothing computed until iteration auto result = nums | std::views::filter([](int n) { return n % 2 == 0; }) | std::views::transform([](int n) { return n * n; }) | std::views::take(3); for (auto x : result) std::print("{} ", x); // 4 16 36 return 0; }
The range pipeline is lazy — filter and transform produce no output until the for loop pulls values through. No intermediate vectors, no allocations.
06 — The Whole Picture
Unreal Engine, game engines, real-time renderers — the performance ceiling of C++ powers interactive media.
Where microseconds matter, C++ is the only option. Latency is measured in cache misses, not abstraction layers.
C++ code written in 1998 still compiles today. That longevity is a deliberate design value.
OOP, generic, functional, procedural — C++ supports them all and lets you pick the right tool for each problem.
RAII with no garbage collector, predictable destruction, and no runtime — ideal for real-time embedded code.
Chromium, LLVM, most databases, video codecs — the software that runs the internet is written in C++.