C++ is a general-purpose, statically typed, compiled programming language that extends C with classes, templates, RAII-based resource management, and the Standard Template Library — providing zero-overhead abstractions for systems programming, game engines, and high-performance applications.
📑 C++ Reference — All Topics
Constructors, destructors, copy/move semantics, RAII.
Function templates, class templates, vector, map, algorithm.
C++11/14/17/20/23: auto, lambdas, smart pointers, concepts.
Nearly 50 years old — and C++26 just finished standardization in March 2026.
GCC, Clang, or MSVC — a feature being in the standard doesn't mean your compiler has it yet.
auto never makes C++ dynamically typed — the type is still fixed at compile time.
The range-based for loop eliminated most manual index bookkeeping, and its bugs too.
C has no overloading at all — C++ resolves it by parameter types, at compile time.
Forget virtual, and an overridden method silently calls the BASE version instead.
unique_ptr can't be copied, only moved — which guarantees zero chance of a double-free.
std::move() doesn't move anything itself — it's purely a cast, nothing more.
Not a pointer in disguise — a true alias that can never be reseated or null.
std::string's + isn't compiler magic — it's the same mechanism your own class can use.
vector should be your default — reach for list only with a specific reason.
A hand-written sort loop is more likely to have a bug than std::sort itself.
[=] copies, [&] references — and getting it wrong dangles a real reference.
Stack unwinding calls every local destructor automatically — RAII makes exceptions safe.
Two libraries can each define a Vector class with zero conflict between them.
Forget join() on a std::thread, and the whole program calls std::terminate.
A bad template argument used to mean pages of unreadable error — not anymore.
C++20 shipped the keywords — almost no ready-to-use types to pair them with.
Mixing new with delete[] is undefined behavior — one more reason to avoid both.
Two shared ancestors, one diamond problem — virtual inheritance is the fix.
A macro has zero type checking — constexpr and templates do the job better.
std::expected finally gives C++ a typed way to return a value or an error.
CMake never compiles anything itself — it generates the files that do.
No built-in test runner exists — Google Test and Catch2 fill that real gap.
push_back can silently invalidate every iterator into the vector.
C++11 was such an overhaul it's often called the language's second birth.
C++ gives you everything C offers — raw performance, direct hardware access, manual memory management — and layers on top the most powerful abstraction mechanisms in any mainstream language: classes, templates, and RAII.
What C++ is
C++ is a general-purpose, statically typed, compiled programming language created by Bjarne Stroustrup at Bell Labs, evolving from "C with Classes" (1979) to C++ with its first standardisation in 1998 (C++98). C++ extends C with classes, inheritance, operator overloading, templates (generic programming), exceptions, namespaces, and the Standard Template Library (STL). C++ compiles to native machine code with zero runtime overhead — no VM, no garbage collector. Memory management is manual (like C) but disciplined through RAII: resources are acquired in constructors and released in destructors, making cleanup automatic and exception-safe.
C++ is used wherever maximum performance and control are required: game engines (Unreal Engine, Unity runtime), browsers (Chromium, Firefox), compilers (Clang, GCC), databases (MySQL, MongoDB), high-frequency trading systems, embedded firmware, and virtually every operating system component. It is one of the most complex mainstream languages — ISO C++23 spans over 2,000 pages.
#include <iostream>
#include <string>
#include <vector>
int main() {
// C++ streams replace printf
std::cout << "Hello, World!" << std::endl;
// std::string — not a char array
std::string name = "Priya";
std::cout << "Hello, " << name << "!" << std::endl;
// std::vector — dynamic array (not a C array)
std::vector<int> scores = {95, 88, 72, 91};
scores.push_back(85);
// Range-based for loop (C++11)
for (int score : scores) {
std::cout << score << " ";
}
std::cout << std::endl;
// auto — type inference (C++11)
auto pi = 3.14159;
auto message = std::string("typed as string");
return 0;
}Classes and OOP
#include <iostream>
#include <string>
#include <stdexcept>
class BankAccount {
private:
std::string owner_; // trailing _ convention for members
double balance_;
public:
// Constructor
BankAccount(std::string owner, double balance)
: owner_(std::move(owner)), balance_(balance) {}
// Destructor — runs automatically when object goes out of scope
~BankAccount() {
std::cout << owner_ << " account closed\n";
}
void deposit(double amount) {
if (amount <= 0) throw std::invalid_argument("Amount must be positive");
balance_ += amount;
}
double getBalance() const { return balance_; } // const = does not modify
// Operator overloading
friend std::ostream& operator<<(std::ostream& os, const BankAccount& acc) {
return os << "Account(" << acc.owner_ << ": " << acc.balance_ << ")";
}
};
int main() {
BankAccount acc("Priya", 1000.0);
acc.deposit(500.0);
std::cout << acc << std::endl; // Account(Priya: 1500)
} // acc.~BankAccount() called automatically hereRAII — Resource Acquisition Is Initialisation
RAII is C++'s most important idiom. It ties resource lifetimes (memory, file handles, network connections, mutexes) to object lifetimes. When an object is constructed, it acquires a resource. When the object is destroyed (goes out of scope), the destructor releases it — automatically and even during stack unwinding from exceptions. This makes C++ resource management safe without a garbage collector. Smart pointers are RAII wrappers around raw pointers.
#include <memory>
#include <fstream>
#include <iostream>
void process_file(const std::string& path) {
// RAII: file closed automatically when stream goes out of scope
std::ifstream file(path);
if (!file.is_open()) throw std::runtime_error("Cannot open: " + path);
std::string line;
while (std::getline(file, line)) {
std::cout << line << "\n";
}
} // file.~ifstream() closes the file here — even if exception thrown
void smart_pointers() {
// unique_ptr: single owner — freed when pointer goes out of scope
auto p1 = std::make_unique<int>(42);
std::cout << *p1 << "\n"; // 42
// p1 freed automatically here
// shared_ptr: reference-counted — freed when last owner gone
auto p2 = std::make_shared<std::string>("hello");
auto p3 = p2; // both p2 and p3 own the string
std::cout << p2.use_count() << "\n"; // 2
} // string freed here when both p2 and p3 destroyedTemplates
C++ templates enable generic programming — writing code that works for any type, resolved at compile time. Unlike Java generics (erased at runtime) or Go generics, C++ templates are fully reified: the compiler generates a specialised version of the code for each type it is used with. This enables maximum performance (no boxing, no virtual dispatch overhead) but increases compile time and binary size.
#include <iostream>
#include <vector>
#include <algorithm>
// Function template
template<typename T>
T max_val(T a, T b) { return a > b ? a : b; }
// Class template
template<typename T>
class Stack {
std::vector<T> data_;
public:
void push(T val) { data_.push_back(std::move(val)); }
T pop() {
if (data_.empty()) throw std::runtime_error("empty stack");
T val = std::move(data_.back());
data_.pop_back();
return val;
}
bool empty() const { return data_.empty(); }
};
// Template with concept constraint (C++20)
template<typename T>
requires std::totally_ordered<T>
T clamp(T val, T lo, T hi) {
return std::clamp(val, lo, hi);
}
int main() {
std::cout << max_val(3, 7) << "\n"; // 7 (int)
std::cout << max_val(3.14, 2.71) << "\n"; // 3.14 (double)
Stack<std::string> s;
s.push("hello");
s.push("world");
std::cout << s.pop() << "\n"; // world
}Move semantics and the rule of five
C++11 introduced move semantics — transferring ownership of resources from one object to another without copying. A move constructor and move assignment operator "steal" the internal resources of a temporary or expiring object (an rvalue) rather than copying them. The rule of five: if you define any of (1) destructor, (2) copy constructor, (3) copy assignment, (4) move constructor, (5) move assignment, you should define all five — because a custom destructor implies resource management that the compiler's defaults won't handle correctly.
#include <iostream>
#include <string>
class Buffer {
char* data_;
size_t size_;
public:
explicit Buffer(size_t size) : data_(new char[size]), size_(size) {
std::cout << "Allocated " << size << " bytes\n";
}
~Buffer() { delete[] data_; } // destructor
// Copy constructor — expensive: copies all data
Buffer(const Buffer& other) : data_(new char[other.size_]), size_(other.size_) {
std::copy(other.data_, other.data_ + size_, data_);
std::cout << "Copied " << size_ << " bytes\n";
}
// Move constructor — cheap: steals the pointer
Buffer(Buffer&& other) noexcept
: data_(other.data_), size_(other.size_) {
other.data_ = nullptr; // leave source in valid empty state
other.size_ = 0;
std::cout << "Moved\n";
}
// Copy/move assignment omitted for brevity — should follow same pattern
};
Buffer makeBuffer() { return Buffer(1024); } // NRVO or move
int main() {
Buffer b1(512); // Allocated
Buffer b2 = b1; // Copied (b2 is independent copy)
Buffer b3 = std::move(b1); // Moved (b1 now empty)
Buffer b4 = makeBuffer(); // Moved or NRVO (no copy)
}The Standard Template Library (STL)
The STL provides containers, algorithms, and iterators as orthogonal components. Containers: vector (dynamic array), map/unordered_map (sorted/hash map), set/unordered_set, list (doubly linked), deque, stack, queue, priority_queue. Algorithms: sort, find, transform, accumulate, count_if, copy. Any algorithm works with any container via iterators — the decoupling that makes the STL extensible.
#include <vector>
#include <map>
#include <algorithm>
#include <numeric>
#include <iostream>
int main() {
std::vector<int> v = {5, 2, 8, 1, 9, 3};
// Algorithms work on any container via iterators
std::sort(v.begin(), v.end()); // in-place sort
auto it = std::find(v.begin(), v.end(), 8); // O(n) find
// transform: apply function to each element
std::vector<int> squared(v.size());
std::transform(v.begin(), v.end(), squared.begin(),
[](int x) { return x * x; }); // C++11 lambda
// accumulate: fold
int sum = std::accumulate(v.begin(), v.end(), 0);
// Ordered map (red-black tree internally)
std::map<std::string, int> word_count;
word_count["hello"]++;
word_count["world"]++;
for (auto& [word, count] : word_count) { // C++17 structured bindings
std::cout << word << ": " << count << "\n";
}
}Modern C++ (C++11 through C++23)
| Standard | Key additions |
|---|---|
| C++11 | auto, range-for, lambdas, move semantics, smart pointers, constexpr, thread, nullptr, initialiser lists |
| C++14 | Generic lambdas, variable templates, [[deprecated]] |
| C++17 | Structured bindings, if constexpr, std::optional, std::variant, std::filesystem, fold expressions, parallel algorithms |
| C++20 | Concepts, ranges, coroutines (co_await), modules, std::format, span, three-way comparison (<=>) |
| C++23 | std::expected, std::print, std::stacktrace, std::generator, import std |
new and delete are error-prone — they require matching every new with a delete and are not exception-safe. In modern C++ (C++11+), use std::make_unique and std::make_shared instead. Raw pointers should only appear at low-level API boundaries.-fno-exceptions) and use error codes instead.The C++ object model and vtables
C++ virtual dispatch uses a vtable (virtual function table). For each class with virtual functions, the compiler generates a vtable: an array of function pointers, one per virtual function. Each object of that class stores a hidden vptr (vtable pointer) as its first data member. Calling a virtual function: dereference vptr to get the vtable, then call the function at the correct index. Cost: two pointer dereferences + one indirect call — typically one cache miss on first call, then cached. final (C++11) allows the compiler to devirtualise calls when the dynamic type is known. Devirtualisation is a key optimisation — the compiler can often prove at compile time which function will be called and inline it, eliminating virtual dispatch entirely.
Template metaprogramming and constexpr
C++ templates were shown to be Turing-complete by Erwin Unruh in 1994 — the compiler emits prime numbers as warning messages at compile time. Template metaprogramming (TMP) is a technique where computation happens entirely at compile time in the type system. C++11 constexpr made compile-time computation more accessible: functions marked constexpr can execute at compile time when their inputs are compile-time constants. C++20 concepts constrain template parameters with readable error messages instead of the famously cryptic TMP error walls. C++20 consteval forces compile-time evaluation.
The C++ Core Guidelines and safe subsets
Bjarne Stroustrup and Herb Sutter maintain the C++ Core Guidelines (github.com/isocpp/CppCoreGuidelines) — a collaboratively developed set of rules for writing correct, efficient modern C++. Key rules: use smart pointers (never raw new/delete), avoid raw arrays (use std::array or std::vector), use std::span for non-owning views. The Guideline Support Library (GSL) provides gsl::span, gsl::not_null, and other helper types. The US NSA and CISA (2022–2024) have recommended that new systems software be written in memory-safe languages instead of C/C++, citing that 70% of Microsoft and Google CVEs are memory safety issues in C/C++ code.
ISO/IEC 14882:2020 — C++20 standard. iso.org/standard/79358.html. Stroustrup, B. (2013). The C++ Programming Language (4th ed.). Addison-Wesley. Meyers, S. (2014). Effective Modern C++. O'Reilly Media. C++ Core Guidelines: github.com/isocpp/CppCoreGuidelines.