Skip to content
C++ logo

C++

First appeared 1985 (as 'C with Classes' from 1979) · Bjarne Stroustrup

Zero-overhead abstraction — you pay only for what you use, and what you use is fast.

Overview

C++ is a high-level, general-purpose programming language created as an extension of the C language by Bjarne Stroustrup in the early 1980s. It incorporates object-oriented, procedural, and generic programming features, making it extremely versatile and powerful. C++ has been widely used for developing operating systems, game engines, real-time simulations, high-performance applications, and large-scale enterprise software. Its combination of low-level memory control and high-level abstractions allows developers to write both efficient system-level code and complex application logic. The language provides features such as classes, inheritance, polymorphism, templates, exception handling, and the Standard Template Library (STL), which includes containers, algorithms, and iterators. Over the decades, C++ has influenced many modern languages including C#, Java, and Rust, and remains a cornerstone of software development in areas requiring performance and reliability. The language continues to evolve through ISO standardization, ensuring modern features while maintaining backward compatibility. C++’s rich ecosystem includes compilers, IDEs, libraries, and tools that support development across multiple platforms, from embedded systems to large-scale enterprise applications.

Key facts

The reference details, without the paragraph.

First appeared
1985 (as 'C with Classes' from 1979)
Designed by
Bjarne Stroustrup at Bell Labs
Typing
Static and strong, with templates providing compile-time generic programming
Execution
Compiled ahead of time to native machine code
Memory model
Manual, but managed through RAII and smart pointers rather than raw `new`/`delete`
Package manager
vcpkg or Conan; no official standard
File extensions
.cpp, .cc, .hpp, .h, .ixx
Current standard
C++23, with C++26 in progress and C++17/20 most common in production
Guiding principle
Zero-overhead abstraction — unused features cost nothing at runtime
Licence
Open ISO standard; GCC, Clang and MSVC implement it independently

History

How the language got here — the decisions that still shape how you write it.

C++ was created by Bjarne Stroustrup at Bell Labs in the early 1980s as an enhancement to the C programming language, aiming to combine the efficiency of C with higher-level abstractions to support large-scale software development. Initially called 'C with Classes', it introduced features such as classes, inheritance, and strong type checking while maintaining compatibility with existing C code. Over the years, C++ evolved into a mature language with multiple paradigms, including procedural, object-oriented, and generic programming, enabling developers to tackle a wide variety of problems. The Standard Template Library (STL), added in the 1990s, brought standardized containers, algorithms, and iterators, simplifying common programming tasks and promoting code reuse. C++ has been fundamental in building critical systems, including operating systems, real-time simulations, graphical engines, compilers, and databases. Its performance and flexibility have made it the language of choice for applications where efficiency is paramount, such as video games, financial software, and embedded systems. The language has been continuously updated through ISO standards (C++98, C++03, C++11, C++14, C++17, C++20, and upcoming C++23), adding features like auto typing, smart pointers, concurrency support, lambda expressions, modules, and enhanced template programming. Bjarne Stroustrup’s vision emphasized both power and maintainability, making C++ suitable for both system-level programming and complex application development. The C++ community is large and active, organizing conferences, maintaining open-source libraries, and contributing to the language’s evolution. C++’s influence on modern computing is profound; many programming languages, frameworks, and software engineering practices have drawn inspiration from its design principles. Its combination of performance, flexibility, and expressive power ensures that C++ remains a critical language for software developers worldwide, continuing to shape the future of computing.

  1. 1979

    C with Classes

    Bjarne Stroustrup, wanting Simula's abstractions with C's efficiency for his distributed systems research, starts adding classes to C at Bell Labs.

  2. 1985

    C++ released

    Renamed with the increment operator, and given virtual functions, operator overloading and references. *The C++ Programming Language* is published the same year.

  3. 1998

    C++98 and the STL

    The first ISO standard incorporates Alexander Stepanov's Standard Template Library. Containers, iterators and algorithms as separate, composable pieces is a genuinely novel design and still the library's foundation.

  4. 2011

    C++11 — 'a new language'

    Move semantics, `auto`, lambdas, range-based `for`, smart pointers, `nullptr` and a threading model arrive together. Stroustrup describes it as feeling like a new language, and modern C++ dates from here.

  5. 2014–2017

    Steady refinement

    C++14 smooths C++11's rough edges; C++17 adds structured bindings, `std::optional`, `std::variant`, `string_view`, filesystem support and parallel algorithms.

  6. 2020

    C++20 — the big four

    Concepts finally make template errors readable, ranges make algorithms composable, coroutines give first-class async, and modules begin to address the header model's compile-time cost.

  7. 2023

    C++23

    `std::expected` for error handling without exceptions, `std::print`, multidimensional subscripting, and a considerably more usable ranges library.

  8. Today

    Where performance is non-negotiable

    Game engines, browsers, databases, trading systems, CAD, and the machine-learning frameworks whose Python interfaces get the credit — all C++ underneath.

What it is good at

The reasons teams pick it, stated concretely.

  • Abstraction without a runtime tax

    Templates and inlining mean a `std::sort` over a custom comparator compiles to code as tight as a hand-written loop. You can build expressive interfaces and still generate the machine code you would have written by hand.

  • RAII solves resource management

    Tie a resource's lifetime to an object's scope and it is released automatically, including when an exception unwinds. Files, locks, sockets and memory all follow one rule. It is arguably C++'s most important contribution to language design.

  • Complete control when you need it

    Memory layout, allocation strategy, alignment, cache behaviour and whether a call is virtual are all yours to decide. In a domain where a microsecond matters, no managed language can offer this.

  • A remarkable standard library

    Containers, algorithms, ranges, threading, chrono, regex and filesystem — all templated, all generic, all fast. `std::sort` is typically an introsort that outperforms most hand-rolled attempts.

  • Compile-time computation

    `constexpr` and `consteval` let real work happen during compilation — lookup tables, parsing, validation — so the binary does nothing at startup that could have been settled by the compiler.

Trade-offs

Every language costs you something. Knowing what, before you commit, is the whole point.

  • The language is enormous

    The standard runs past 2,000 pages. There are several dialects in active use — C++98-with-classes, modern C++11-and-later, and template-heavy library code — and reading all three well takes years.

  • The same memory hazards as C, unless you are disciplined

    Dangling references, iterator invalidation and use-after-free are all reachable. Modern practice — smart pointers, containers, no raw `new` — avoids most of them, but nothing enforces it.

  • Template error messages

    A single mistake can produce hundreds of lines of instantiation trace. C++20 concepts improve this substantially, but a lot of existing library code predates them.

  • Slow compilation

    Header inclusion means the same code is parsed repeatedly across translation units. Large projects measure builds in tens of minutes. Precompiled headers, forward declarations, unity builds and modules all help, none fully solve it.

  • No standard package management

    vcpkg and Conan work well, but they are conventions rather than a language feature, and CMake remains the price of entry for cross-platform builds.

Code examples

Not syntax tours — the idioms that make code read like the language rather than a translation of another one.

RAII — the idea the language is built around
#include <fstream>
#include <mutex>
#include <memory>

class Logger {
    std::ofstream file_;
    std::mutex    mutex_;
public:
    explicit Logger(const std::string& path) : file_(path, std::ios::app) {
        if (!file_) throw std::runtime_error("cannot open log");
    }

    void write(std::string_view line) {
        std::lock_guard<std::mutex> guard(mutex_);  // unlocks on scope exit
        file_ << line << '\n';
    }
    // No destructor needed: ofstream closes itself, mutex cleans itself up.
};

auto logger = std::make_unique<Logger>("app.log");
logger->write("started");   // freed automatically when the pointer goes out of scope
The destructor runs on every exit path — normal return, early return, or an exception unwinding the stack. `lock_guard` releases the mutex even if `write` throws, which is why C++ needs no `finally` block.
Smart pointers express ownership in the type
#include <memory>
#include <vector>

struct Node {
    int value;
    std::vector<std::unique_ptr<Node>> children;   // exclusive ownership
    Node* parent = nullptr;                        // non-owning back-reference
};

auto root = std::make_unique<Node>(Node{1, {}, nullptr});
auto child = std::make_unique<Node>(Node{2, {}, root.get()});
root->children.push_back(std::move(child));
// child is now empty; root owns the whole tree and frees it in one go.
`unique_ptr` cannot be copied, only moved, so the compiler enforces that exactly one owner exists. The raw `parent` pointer is deliberate: it observes without owning, which is what prevents a reference cycle. Use `shared_ptr` only when ownership is genuinely shared — it costs an atomic refcount.
Ranges compose algorithms without temporaries
#include <ranges>
#include <vector>
#include <print>

std::vector<int> readings{12, -3, 45, 7, -18, 33, 21};

auto top = readings
    | std::views::filter([](int n) { return n > 0; })
    | std::views::transform([](int n) { return n * 2; })
    | std::views::take(3);

for (int value : top) std::print("{} ", value);   // 24 90 14
Views are lazy: nothing is computed until the loop pulls a value, and no intermediate vector is allocated. Compare this with the pre-C++20 form, which needed named iterators and a temporary container for each step.
Templates with concepts, so the errors make sense
#include <concepts>
#include <ranges>

template <std::ranges::input_range R>
    requires std::totally_ordered<std::ranges::range_value_t<R>>
auto largest(const R& range) {
    auto it = std::ranges::max_element(range);
    return it == std::ranges::end(range)
         ? std::nullopt
         : std::optional{*it};
}

auto biggest = largest(std::vector{3, 9, 4});   // std::optional<int>{9}
// largest(42);  // error names the failed constraint, not 200 lines of template trace
Concepts state the requirements a type must meet as part of the signature. When a caller violates them the compiler says which constraint failed — the single biggest quality-of-life improvement in C++20.

Common pitfalls

The mistakes that cost everyone an afternoon at least once.

  • Raw `new` and `delete`

    Every manual `delete` is a leak waiting for an early return or an exception. Use `make_unique`, `make_shared` and containers; in modern C++ you should rarely write either keyword.

  • Iterator and reference invalidation

    `push_back` may reallocate a vector, invalidating every existing iterator, pointer and reference into it. Erasing inside a loop invalidates too — use the iterator returned by `erase`.

  • Object slicing

    Assigning a derived object to a base-class variable copies only the base part and silently discards the rest. Store polymorphic objects by reference or smart pointer, never by value.

  • Dangling `string_view` and references

    `string_view` does not own its characters. Binding one to a temporary — or returning one that refers to a local — leaves you reading freed memory.

  • Copying where a move would do

    Passing large containers by value in a hot path copies them. Take by `const&` to observe, by value plus `std::move` to take ownership.

  • Forgetting a virtual destructor

    Deleting a derived object through a base pointer without a virtual destructor is undefined behaviour and skips the derived destructor. Any class meant for inheritance needs one.

In production

Where it is running at scale, and what it is doing there.

  • Adobe

    Desktop applications like Photoshop and Illustrator.

  • Microsoft

    Windows OS components, Office suite, and high-performance apps.

  • Google

    High-performance backend systems and Chrome browser.

  • Epic Games

    Game engine development (Unreal Engine) and game development.

Learning path

A realistic order to learn things in, with something to build at each step.

  1. 1

    Weeks 1–3

    Core language, modern style from the start

    Types, functions, references, `auto`, range-based `for`, `std::string` and `std::vector`. Learn the modern idioms first — do not start with `new`, `delete` and raw arrays and unlearn them later.

    Build this: Write a program that reads words from a file and reports frequencies using `std::map`.

  2. 2

    Weeks 4–6

    Classes, RAII and the object model

    Constructors and destructors, the rule of zero, copy versus move, `const` correctness, and why RAII matters. Understand what happens when an exception propagates through your objects.

    Build this: Implement a resource wrapper — a file handle or buffer — that is correct under copy, move and exception.

  3. 3

    Weeks 7–10

    The standard library

    Containers and their complexity guarantees, iterators, algorithms, `std::optional`, `std::variant`, `string_view`, smart pointers, and `chrono`. Knowing what is already in the library prevents most reinvention.

    Build this: Rewrite earlier code using standard algorithms instead of hand-written loops and measure the difference.

  4. 4

    Months 4–6

    Templates, concurrency and builds

    Function and class templates, `constexpr`, concepts, threads, `std::atomic` and the memory model, plus CMake and a package manager. This is where C++ becomes genuinely powerful.

    Build this: Build a thread-safe queue and a small CMake project that consumes an external dependency.

  5. 5

    Ongoing

    Performance and correctness in earnest

    Cache behaviour and data-oriented design, move semantics in depth, profiling with perf or VTune, sanitisers, and the C++ Core Guidelines. Read the standard library implementation when a question gets specific.

    Build this: Profile a hot loop and improve it by changing the data layout rather than the algorithm.

Ecosystem and tooling

The tools you will end up installing whichever project you join.

ToolWhat it does
CMakeThe de facto cross-platform build system; almost every library expects it
vcpkg / ConanDependency managers that make third-party libraries a one-line addition
GCC / Clang / MSVCThe three major compilers; testing against more than one catches non-portable assumptions
Catch2 / GoogleTestThe standard unit-testing frameworks — Catch2 is header-only, GoogleTest has richer mocking
AddressSanitizer / ThreadSanitizerRuntime detection of memory errors and data races
clang-tidy / clang-formatStatic analysis against the Core Guidelines, and automatic formatting
Compiler ExplorerSee the assembly your code generates across compilers and flags — invaluable for understanding cost
perf / VTuneSampling profilers for finding where the time actually goes

C++ libraries

43 catalogued, each with installation, worked examples and best practices.

Frequently asked

Is C++ still worth learning?

Yes, in the domains where it is the answer: game engines, browsers, databases, embedded systems, high-frequency trading, robotics, and the compute kernels behind machine-learning frameworks. It is not the right first language for web or scripting work, and it is not going anywhere in the fields that need it.

What is 'modern C++' and why does it matter?

C++11 and later, written with smart pointers, containers, `auto`, range-based loops, move semantics and RAII rather than raw pointers and manual memory. It is a genuinely different experience from the C++ of the 1990s — and much of the material online still teaches the old style.

C++ or Rust for a new systems project?

Rust if memory safety is the priority and the team can absorb the borrow checker's learning curve. C++ if you need a mature ecosystem in your domain — graphics, audio, CAD, scientific computing — or must integrate with a large existing codebase. Both compile to comparable machine code.

Which standard should I target?

C++20 for a new project on current toolchains: concepts and ranges alone justify it. C++17 is the widely safe baseline. Avoid starting anything new at C++11 or earlier unless a platform constraint forces it.

How do I keep compile times reasonable?

Include less in headers — forward declare where you can — use precompiled headers, split large translation units, cache with ccache, and prefer explicit instantiation for heavy templates. Modules address the root cause and are increasingly usable.

Should I use exceptions?

For most applications, yes — they keep error handling out of the happy path and are effectively free when nothing throws. Game engines and embedded projects often disable them for deterministic timing and binary size, in which case `std::expected` in C++23 gives a good alternative.