Welcome + the C++ Mental Model
Why C++ in 2026, and what `g++ main.cpp` actually does
Why this course exists
Most C++ tutorials teach you the language Java would have written if Java had no
garbage collector. You inherit, you new, you delete, you remember the
destructor, you cry into the segfault.
This course teaches the language that wins benchmarks and ships into your phone’s kernel, your browser’s JIT, and the firmware on the satellite reading this page back to you over Starlink. Modern C++ is value-semantics-first. Inheritance hierarchies are de-emphasized. Exceptions are a tool of last resort. The standard library is mostly free functions over generic iterators.
The goal: leave you able to read library code without flinching. Not to memorize the standard.
Why C++ in 2026
Languages overlap, and most of them solve “write a program” perfectly well. C++ is the answer when one of these is non-negotiable:
- Zero-cost abstractions. A
std::sortcall compiles to the same instructions as a hand-rolled quicksort on the same types. The wrapper isn’t paying rent at runtime. - Deterministic destruction. When a
std::unique_ptr<File>falls out of scope, the file closes. Not when a garbage collector feels like it. Not “soon.” Now. - Predictable layout. A
structis the bytes it says it is. Cache lines matter, prefetching matters, and you can ask for both. - Reach. From a Mars rover’s flight computer to a $60 Steam Deck game. Same language, often the same standard library.
If none of those is on your critical path, pick a different language and be happier. If even one is — welcome.
How a C++ program becomes a thing that runs
You can write Python by typing into a REPL. You cannot write C++ that way, and
the reason is half the curriculum. Every .cpp file you author makes a trip
through this pipeline before it executes:
main.cpp ┌──────────────┐
│ │ preprocessor│ expands #include,
▼ └──────┬───────┘ resolves #define
main.i (the "translation unit") │
│ ▼
│ ┌──────────────┐
▼ │ compiler │ parses, type-checks,
main.s (assembly) └──────┬───────┘ emits assembly
│ │
│ ▼
▼ ┌──────────────┐
main.o (object file) │ assembler │ → machine code,
│ └──────┬───────┘ with unresolved symbols
│ │
│ ┌── libstdc++.so ──┐ │
│ │ │ ▼
▼ ▼ │ ┌──────────────┐
┌──────────────┐ │ │ linker │ glues object files +
│ linker │ ◀────────┘ └──────┬───────┘ libraries, resolves
└──────┬───────┘ │ symbol references
│ ▼
▼ ./a.out (runs!)
When you type g++ main.cpp, the compiler driver runs all four stages and
throws away the intermediates. You can ask it to stop after any one:
g++ -E main.cpp— preprocessor only. Print the expanded source.g++ -S main.cpp— stop at assembly. Look atmain.s.g++ -c main.cpp— stop at object file. Look atmain.o.g++ main.cpp -o hello— go all the way, name the binaryhello.
The linker is the part beginners trip over most. When you write
std::cout << "hi", the compiler doesn’t contain std::cout. It just
records that main.o will need a symbol called std::cout at link time. The
linker is what walks the standard-library archive and fills in the blank. A
“linker error” is the linker asking: I have this hole, and nothing on the
shelf fits it.
The smallest possible program
#include <iostream>
int main() {
std::cout << "hello, " << "world\n";
return 0;
}
Six lines, four pipeline stages, one ABI contract with the OS.
hello, world Or run locally
g++ -std=c++23 -O2 snippet.cpp && ./a.out Read it like a translator:
#include <iostream>— the preprocessor pastes in roughly 30,000 lines of declarations.#includeis notimport. It is literal text inclusion. The compiler then has to type-check all of it. (This is why C++ builds are slow. Modules, introduced in C++20, are the long-promised fix.)int main()— the function the OS calls to start your program. The name is hard-coded in the platform’s startup code. Return typeintbecause the shell wants an exit code.std::cout << "hello, "—coutis an object in namespacestd.<<is an operator overload on that object that takes aconst char*and writes it. It returnscoutagain, which is why you can chain.return 0;— by convention, zero means success. The kernel reports this back to whoever ran you (echo $?to see it).
Six readable lines hide a translation unit of about 30,000 expanded ones, one function the OS recognizes by name, a globally-instantiated stream object, and two operator overloads. Modern C++ is mostly about learning to see all that without it slowing you down.
What “value semantics” means before we go deeper
One sentence preview, because it’s the spine of the whole course:
When you write
auto y = x;, you got a copy. Not a reference, not a pointer, not a handle. A whole newx, byte-for-byte. Changingycannot changex.
This is the opposite of Python (y = x makes y an alias) and the opposite
of Java (y = x aliases for objects, copies for primitives). C++ defaults to
copy, and the type author decides what “copy” means. That decision — and the
machinery around moves, references, and ownership that lets you avoid copies
when they’d be wasteful — is the lesson 06 payoff.
Key takeaways
- C++ wins when zero-cost abstractions, deterministic destruction, predictable layout, or reach matter. Otherwise pick something else.
- The translation pipeline has four stages — preprocessor, compiler, assembler, linker — and the linker is the one that surprises beginners.
#includeis text inclusion, not import. Modules (C++20) are the fix but aren’t universal yet.int main()is the entry point because the OS’s startup stub calls a symbol of that name. Theintis the exit code.- C++ is copy-by-default. Everything that’s interesting about modern C++ flows from making that default cheap to opt out of when you want to.
What’s next
Lesson 01 picks up where the hello world ends: what is a std::string,
what’s it costing you, and why int x = 5; and int& y = x; are two very
different things. Then lesson 03 opens the box on stack vs heap with the
memory diagrams this course is going to lean on hard.
If you want to flex first, here’s the project this course builds toward:
Capstone C1 — Custom Allocator. Write a slab allocator that beats
new/deleteon a real workload. Profile it. Plug it intostd::vectorviastd::pmr. Convince yourself the abstraction really is zero-cost.
That’s the proof of the language. Everything between here and there is runway.