By Bogdan Sandu · Updated August 14, 2026
What is C++
C++ is a compiled, statically typed, general-purpose language that extends C with object-oriented and generic programming support.
Bjarne Stroustrup began building it at Bell Labs in 1979 under the name "C with Classes," renaming it C++ in 1983.
Three compilers dominate production builds today: GCC 15.3 (released June 12, 2026), Clang 22.1.3 (released April 7, 2026), and Microsoft's MSVC, bundled with Visual Studio.
TechRepublic's August 2026 TIOBE Index puts C++ at No. 3 among all programming languages, with an 8.62% share, just ahead of Java's 8.25%.
Usage figures back that ranking. 23.5% of developers in the 2025 Stack Overflow Developer Survey reported working with C++ in the past year, rising to 44.6% among people currently learning to code.
The language still anchors a large share of modern software development, particularly where raw speed and hardware control matter more than rapid iteration.
C++ Standard Versions
C++98, the language's first ISO standard, arrived in 1998. Six standards followed it, each layering new capability onto the language without breaking most existing code:
| Standard | Ratified | Key Addition |
| C++11 | 2011 | auto, lambdas, smart pointers |
| C++14 | 2014 | generic lambdas, relaxed constexpr |
| C++17 | 2017 | structured bindings, std::optional |
| C++20 | 2020 | concepts, coroutines, modules |
| C++23 | 2024 (ISO/IEC 14882:2024) | multidimensional subscript operator |
| C++26 | 2026 | reflection, contracts |
WG21 technically finalized C++26 in London on March 28, 2026. Committee chair Herb Sutter described its compile-time reflection feature as "a whole new language."
Adoption of the newest standard is already measurable. Stack Overflow's rising-technology tag for c++23 was used by 7.3% of all 2025 survey respondents, ahead of several newer frameworks tracked that same year.
Where C++ Is Used
Four industries account for most production C++ code.
- Game engines, most visibly Epic Games' Unreal Engine
- Operating system kernels and device drivers
- Embedded and aerospace firmware, including flight software
- Low-latency trading systems in finance
A growing fifth category has emerged. TIOBE's own August 2026 commentary notes that a meaningful share of the infrastructure running AI models in production is written in C++, prized for the same low-overhead execution that made it standard in game engines decades earlier.
Data Types and Variables in C++
C++ requires every variable to carry a fixed type, decided either explicitly or through inference at compile time.
That type determines how many bytes the compiler reserves and which operations are legal on the value.
Primitive Types and Sizes
| Type | Typical Size (64-bit) | Example Value |
| int | 4 bytes | 42 |
| double | 8 bytes | 3.14159 |
| char | 1 byte | 'A' |
| bool | 1 byte | true |
Modifiers change these defaults. signed and unsigned attach to the base types alongside short and long, so unsigned long stores far larger values than a plain int.
Java's own primitive type table borrows this int, double, char split almost unchanged, though Java dropped the unsigned modifiers entirely in favor of the smaller set covered in its own syntax reference.
Variable Declaration Syntax
Copy initialization: int x = 5; assigns through the = operator.
Direct initialization: int x(5); calls the constructor directly.
Brace initialization: int x{5}; blocks narrowing conversions the other two forms allow silently.
auto, added in C++11, infers the type from the right-hand side, so auto x = 5; makes x an int without the word ever appearing.
Google's public C++ Style Guide requires every variable to be initialized at the point of declaration, a rule it enforces across its own production codebase.
Operators in C++
C++ groups its operators into four functional categories.
- Arithmetic:
+ - * / %
- Relational and logical:
== != && ||
- Bitwise:
& | ^ ~ << >>
- Assignment:
= += -= *=
id Software's Quake engine, written largely in C, leaned on a bitwise trick called the fast inverse square root to speed up lighting math, a technique C++ game engines still cite as a case study in bit-level operator use.
Operator Precedence Table
| Precedence | Operators | Associativity |
| Highest | () [] -> . | Left to right |
| Middle | * / % + - | Left to right |
| Lower | && || | Left to right |
| Lowest | = += -= | Right to left |
Precedence beats intuition here. Mixed expressions without parentheses resolve strictly by this order, which is why a * b + c never evaluates as a * (b + c).
Control Flow Statements in C++
Control flow statements decide which lines of a C++ program execute, and how many times.
Every branch and loop in the language reduces to one of a handful of keywords.
Conditional Statements
NASA's Jet Propulsion Laboratory enforces a coding standard, based on Gerard Holzmann's "Power of Ten" rules, that governs the C and C++ running its Mars rovers.
if, else if, and else evaluate boolean expressions in order and execute the first branch that matches.
switch-case compares a single value against multiple constant labels, falling through to the next case unless a break stops it.
The Curiosity rover runs on roughly 2.5 million lines of flight code, all written under rules that forbid unbounded branching paths (RankRed, 2026).
Loop Structures
Four loop forms cover every iteration case in C++.
for (init; condition; increment) for counted iteration
while (condition) for open-ended iteration
do-while for loops that must run at least once
- Range-based
for (C++11) for iterating containers directly
JPL's institutional standard requires every loop to carry a statically provable upper bound, the same rule cited above, so unbounded while(true) constructs are rejected outright in flight software.
break exits a loop early, continue skips to the next iteration, and goto jumps to a labeled line, though most C++ style guides ban goto for the clarity reasons JPL formalized decades ago.
Functions in C++
A function in C++ groups reusable code behind a name, a return type, and a parameter list.
The signature, not just the name, determines which function a given call resolves to.
Function Overloading
Multiple functions can share one name in C++ as long as their parameter lists differ in type, order, or count.
The compiler picks the correct overload at compile time by matching argument types against each candidate signature, a process called overload resolution.
print(int) and print(double) coexist safely. Adding print(std::string) later joins the same overload set without conflict.
Return type alone never distinguishes overloads. Two functions differing only in return type fail to compile.
Lambda Expressions
C++11 introduced lambdas: anonymous, inline functions written as [capture](parameters) { body }.
Capture modes control what a lambda can see from its surrounding scope.
[] captures nothing
[&] captures everything by reference
[=] captures everything by value
[x] captures only x, by value
The C++ Core Guidelines, maintained by Stroustrup and Herb Sutter, recommend passing lambdas as templates or std::function rather than raw function pointers to preserve capture behavior.
Arrays and Strings in C++
C++ offers two ways to store sequences of characters, and two ways to store sequences of any other fixed type.
C-Style Arrays
int values[5]; reserves five contiguous ints, indexed from values[0] through values[4].
Multidimensional arrays stack this pattern: int grid[3][3]; declares a 3-by-3 block in row-major order.
Out-of-bounds access compiles without error and reads or writes whatever memory sits past the array, a common source of the bugs the language's critics point to.
std::array and std::vector wrap this same memory layout with bounds-checked access through .at(), trading a small performance cost for safety.
std::string vs C-Style Strings
C-style strings:
- Stored as char arrays
- Terminated by a null character,
'\0'
- Manipulated through pointer-based functions like
strlen and strcpy
std::string:
- Manages its own memory and resizes automatically
- Exposes methods including
length(), substr(), find(), and append()
- Overloads
+ for concatenation, unlike C-style strings
Meta's open-source Folly library ships a custom fbstring that outperforms the standard std::string on short strings by avoiding a heap allocation entirely.
Pointers and References in C++
A pointer stores a memory address. A reference is an alias for an existing variable.
Both let a function or expression work with data without copying it, but they behave differently once declared.
Pointer Syntax and Arithmetic
int* p declares a pointer to an int. *p dereferences it to read or write the value it points to, and &x takes the address of x.
Pointer arithmetic moves by element size, not by byte, so p + 1 on an int* jumps four bytes ahead on a typical 64-bit build.
Microsoft reports that roughly 70% of the vulnerabilities it assigns a CVE to each year trace back to memory safety issues, and unchecked pointer arithmetic is a leading contributor (Microsoft, via CISA, 2023).
const correctness narrows that risk. const int* p points to a value that can't change through p, while int* const p is a pointer that can't be repointed.
References vs Pointers
Three differences decide which one a given piece of code needs.
- Nullability: a pointer can be
nullptr, a reference must bind to a real object at creation
- Reassignment: a pointer can be redirected later, a reference is locked to its original target for life
- Syntax: pointers need
* to dereference, references behave like the original variable with no extra symbol
Function parameters favor references for this reason. void update(int& x) modifies the caller's variable without the null-check overhead a pointer parameter carries.
Object-Oriented Programming in C++
C++ implements object-oriented programming, one of the core software development principles behind maintainable large-scale codebases, through classes that bundle data and the functions that operate on it into a single type.
Every object built from a class carries its own copy of the data members, while member functions operate on whichever object called them.
Constructors and Destructors
A constructor runs automatically when an object is created, most often to set initial values for its data members.
Qt's widget hierarchy leans on this pattern constantly. Every QWidget subclass initializes its layout and child widgets inside the constructor before the object becomes usable.
Initialization lists run before the constructor body and are the only way to initialize const members or references, since Type(int x) : member(x) {} sets the member before the body ever executes.
A destructor runs automatically when an object goes out of scope or is deleted, releasing whatever resources the constructor acquired. ~ClassName() never takes arguments and never returns a value.
Inheritance and Polymorphism
| Concept | Mechanism | Resolved |
| Inheritance | class Derived : public Base | Compile time |
| Virtual function | virtual return_type name() | Runtime, via vtable |
| Pure virtual | virtual void name() = 0; | Forces override, blocks instantiation |
A base class pointer or reference calling a virtual function executes the derived class's version, the mechanism behind runtime polymorphism.
LLVM's compiler internals lean on the same override pattern. Its abstract syntax tree classes dispatch through a common base Value class shared by every instruction type.
Standard Template Library Containers and Algorithms
The Standard Template Library organizes reusable data structures and functions around three cooperating parts: containers, algorithms, and iterators.
A container holds data, an algorithm processes it, and an iterator connects the two without either side needing to know the other's implementation details.
Container Types
| Category | Examples | Best For |
| Sequence | vector, deque, list, array | Ordered, position-based access |
| Associative | map, set, multimap | Sorted key lookup |
| Unordered | unordered_map, unordered_set | Fast average-case lookup |
| Adapter | stack, queue, priority_queue | Restricted access patterns |
std::vector handles random access and end-insertion in constant time, but inserting mid-sequence costs linear time, per cppreference's own complexity guarantees for the type.
Common STL Algorithms
Four algorithms from the <algorithm> header cover most everyday tasks.
std::sort reorders a range using a comparison function
std::find returns an iterator to the first matching element
std::count tallies elements matching a condition
std::accumulate, from <numeric>, reduces a range to a single value
container.begin() and container.end() return iterators marking the start and one-past-the-end position. rbegin() and rend() do the same in reverse, letting identical algorithm calls traverse a container backward.
Bloomberg's BDE library, open sourced from the same C++ codebase running its trading terminal, extends this iterator-based design with its own container set built to interoperate with the standard one.
Memory Management in C++
C++ gives developers direct control over when memory is allocated and released, unlike languages with automatic garbage collection.
That control is also where most of the language's most serious bugs originate.
Manual Allocation with new and delete
new requests memory from the heap and returns a pointer to it. delete releases that memory back to the system.
Every new needs exactly one matching delete. Calling delete twice on the same pointer, a double-free, corrupts the heap's internal bookkeeping.
Forgetting delete entirely creates a memory leak: the memory stays reserved for the life of the program even though nothing can reach it anymore.
Dangling pointers compound the risk. A pointer that still holds the address of freed memory looks valid to the compiler right up until something dereferences it.
Smart Pointer Types
| Type | Ownership | Header |
| unique_ptr | Single owner, non-copyable | <memory> |
| shared_ptr | Shared, reference-counted | <memory> |
| weak_ptr | Non-owning observer of a shared_ptr | <memory> |
All three, added in C++11, wrap a raw pointer and call delete automatically when the last owner goes out of scope, an application of the broader RAII principle.
MITRE's 2024 CWE Top 25 ranked use-after-free (CWE-416) at No. 4 among the most dangerous software weaknesses, with 1,172 reported CVEs tied to the exact failure mode smart pointers are designed to prevent (MITRE, 2024).
Mozilla's Firefox codebase relies on its own reference-counted smart pointer types, RefPtr and nsCOMPtr, to manage the same ownership problem across its C++ layers.
make_unique and make_shared construct the pointer and its managed object in a single call, keeping a raw new expression out of application code entirely.
Exception Handling in C++
try, catch, and throw let a program separate normal logic from error-handling logic.
Code inside a try block runs normally until a throw statement transfers control to a matching catch block.
std::exception is the base class for the standard library's built-in exception types, including std::runtime_error and std::out_of_range.
Custom exception types typically inherit from std::exception and override its virtual what() method to return a description string.
A single catch block can list multiple exception types, or use catch (...) to intercept anything a more specific handler missed.
Most C++ implementations use what a 2024 technical analysis called a zero-cost exception model: code in a try block carries no runtime overhead as long as no exception is actually thrown.
That claim isn't universal. A 2022 ISO working paper, P2544R0, measured slowdowns near 25% on the non-throwing path under high-concurrency workloads, tracing the cost to a global mutex the unwinder locks to protect its tables. The two findings describe different conditions rather than contradicting each other: true zero-cost holds for single-threaded, rarely-throwing code, while the mutex contention shows up specifically under heavy concurrent throw rates.
LLVM's own coding standards disable C++ exceptions across its codebase entirely, citing binary size and predictable control flow over the performance question itself.
noexcept, added in C++11, tells the compiler a function will never throw, permitting optimizations the compiler can't safely make otherwise.
Input and Output Operations in C++
C++ handles input and output through streams, objects that read or write a sequence of characters regardless of whether the destination is a console, a file, or a string.
Console I/O
fmt::print, the library that became the basis for C++23's std::print, benchmarked roughly 20% faster than printf from Apple's libc, according to the library's own author.
std::cin and std::cout read from and write to the console using the >> and << operators, chaining multiple values in a single statement.
std::print and std::println, added in C++23, close the gap between cout's type safety and printf's speed by writing directly to the underlying file stream instead of routing through iostream's formatting layer.
getline(std::cin, line) reads an entire line, including spaces, which the >> operator on its own stops at.
File I/O
Three stream classes handle file access, each from <fstream>.
ifstream opens a file for reading only
ofstream opens a file for writing only, truncating existing content by default
fstream opens a file for both reading and writing
iomanip provides formatting controls that work on both console and file streams. setw() pads a field, setprecision() limits decimal places, and fixed forces standard decimal notation instead of scientific.
Every open file stream closes automatically when it goes out of scope, another application of the RAII pattern already covered under smart pointers.
Preprocessor Directives and Header Files in C++
The preprocessor runs before compilation, transforming source code through directives that all begin with #.
#include pulls the contents of a header file into the current source file, most commonly for standard headers like <iostream>, <vector>, <string>, and <algorithm>.
#define creates a macro, substituting text before the compiler ever sees it, which is why macro bugs rarely surface as ordinary syntax errors.
Header guards prevent a header from being included twice in the same translation unit.
#ifndef HEADER_H, #define HEADER_H, and #endif form the traditional pattern
#pragma once achieves the same result in one line, supported by every major compiler despite never being formally standardized
C++20 modules offer an alternative to both approaches, importing compiled interfaces instead of reprocessing text on every build. Alibaba Cloud's Hologres team reported roughly a 42% improvement in compilation efficiency after migrating its codebase to modules (Alibaba Cloud, 2025).
Conditional compilation, through #ifdef and #ifndef, compiles different code paths depending on which macros are defined, commonly used to isolate platform-specific code.
Modern C++ Syntax Shortcuts
C++11 through C++23 added syntax that shortens common patterns without changing what the underlying code does.
auto, already covered under variable declaration, extends the same type inference to function return types and lambda parameters.
Range-based for loops, already covered under control flow, iterate a container directly: for (auto& item : container) replaces manual index tracking entirely.
Structured bindings, added in C++17, unpack a pair, tuple, or struct into named variables in one line: auto [key, value] = *map.begin();
nullptr, added in C++11, replaced the older NULL macro with a proper pointer-typed keyword, closing a long-standing source of overload-resolution bugs where NULL silently converts to an integer.
constexpr tells the compiler to evaluate a function or variable at compile time whenever its inputs allow it, moving work out of the running program entirely.
FAQ on C++
What does the ++ in C++ mean?
++ is C's increment operator, meaning "one more than." Bjarne Stroustrup chose the name in 1983 to signal that C++ extends the original C programming language with new features like classes, rather than replacing it outright.
What is the difference between C and C++?
C is a procedural language. C++ adds object-oriented programming, templates, and exception handling on top of it, though most valid C code still compiles as valid C++ with stricter type checking applied.
What is the difference between a struct and a class in C++?
Both group data and functions into one type. The only default difference is access level: struct members are public by default, class members are private, which is why developers typically reach for struct with plain data.
Does C++ have garbage collection?
No. C++ relies on manual memory management and RAII instead of automatic garbage collection. Destructors and smart pointers like unique_ptr and shared_ptr release memory deterministically, without the pause times a garbage collector introduces.
What is undefined behavior in C++?
Undefined behavior is code the C++ standard places no requirements on, like reading past an array's bounds. The compiler can do anything: crash, produce wrong output, or appear to work fine until conditions change.
What is the Rule of Three in C++?
If a class defines a custom destructor, copy constructor, or copy assignment operator, it usually needs all three. Each manages the same resource, so the compiler-generated versions of the other two are likely wrong.
What is move semantics in C++?
Move semantics, added in C++11, let a program transfer ownership of a resource instead of copying it. std::move casts an object to an rvalue reference, so containers like std::vector can relocate data without reallocating memory.
What is the difference between std::endl and \n in C++?
std::endl inserts a newline and flushes the stream's buffer immediately, which is slower under repeated calls. \n writes only the newline character, making it the faster default choice inside performance-sensitive loops.
Is C++ still worth learning?
Yes, particularly for systems programming, game engines, and embedded work where raw performance and hardware control matter. It also builds a mental model of memory and execution that transfers directly to languages like Rust or Java.
A header-only library ships its entire implementation inside header files, with no separate .cpp files to compile or link. Including the header via #include is enough, which trades longer compile times for simpler distribution.