AlgoMaster Logo

History of C++

Low Priority8 min readUpdated June 17, 2026
Listen to this chapter
Unlock Audio

C++ was born in 1979 inside Bell Labs as a side project to make C less painful for large systems work. Almost five decades later, the language has gone through several major reinventions, and the version written today looks little like the version found in older textbooks. This chapter walks through that timeline, from the first "C with Classes" prototype to C++23, and explains why knowing the history helps when reading existing C++ code.

Origins at Bell Labs

In 1979, a Danish computer scientist named Bjarne Stroustrup joined Bell Labs in New Jersey, the same lab that gave the world C, Unix, and the transistor. Stroustrup had just finished his PhD work, where he'd used a language called Simula to simulate a distributed software system. Simula was the first language to ship the ideas we now call object-oriented programming: classes, inheritance, virtual functions, the whole package.

Simula was a pleasant language to write in. It was also slow. When Stroustrup tried to use it for serious system-level work at Bell Labs, the runtime overhead made the language unusable for the problems he had to solve, things like analyzing the call graph of the Unix kernel and modeling network traffic.

C, on the other hand, was fast. It compiled down to tight machine code, it gave direct access to memory, and the Unix folks down the hall were happy to help. But C had no classes, no inheritance, no way to bundle data and behavior together. For a project with thousands of interacting modules, organizing the code in plain C was a constant fight.

Stroustrup started adding Simula's class system onto C. The first version, built in 1979 and used internally at Bell Labs, was called "C with Classes". It was a preprocessor that translated class-style syntax into plain C, which then went through the regular C compiler. Classes, basic inheritance, inline functions, and access control (public, private) all date from this era.

The Pre-Standard Era

By 1983, "C with Classes" had grown enough new features that the name didn't fit anymore. Stroustrup renamed the language to C++. The ++ is the C increment operator, so the name means "C, incremented", a small joke that has aged well.

The first commercial release of C++ came in 1985, along with Stroustrup's book The C++ Programming Language, which served as the de facto specification for years. There was no standards body yet, no ISO committee, only one book and one compiler from AT&T.

Over the next decade, C++ kept growing. Virtual functions came in 1983. Multiple inheritance arrived in 1989. Templates and exceptions showed up in 1990. Namespaces and the early versions of the Standard Template Library (STL) followed in the early 1990s. Each addition made the language more powerful and also harder to learn.

The problem with this era was the lack of an official spec. Different compilers implemented different subsets of the language. Code that compiled on one compiler often failed on another. The community knew this couldn't last.

C++98 and the First Standard

In 1998, the ISO C++ committee (officially known as ISO/IEC JTC1/SC22/WG21) published the first international standard for the language: ISO/IEC 14882:1998, called C++98. This was a big deal. For the first time, there was a single document everyone, compiler vendors, library authors, and developers, could point to and say "this is what C++ means."

C++98 locked in the core language recognizable today: classes, inheritance, virtual functions, templates, exceptions, namespaces, and a standardized version of the STL with std::vector, std::map, std::string, iterators, and algorithms. Older C++ code that uses std::auto_ptr or includes headers with .h suffixes is C++98.

A small follow-up came in 2003, called C++03. It was a "technical corrigendum", a bug-fix release for the standard. No new features. C++03 cleaned up wording issues, fixed defects in the spec, and clarified ambiguous behavior. From a programmer's perspective, C++98 and C++03 are usually treated as the same thing.

The Stagnation Years (2003-2011)

After C++03, the language went quiet. For roughly eight years, no new standard shipped. The committee was working on the next version, originally called "C++0x" (the x was supposed to be a single digit), but the scope kept growing and the deadline kept slipping. Some inside jokes called it "C++1x" once the calendar passed 2009.

Meanwhile, the world moved on. Java dominated enterprise software. Python and Ruby got popular for scripting and web work. C# took over the Windows world. New languages came with garbage collection, simpler syntax, and faster iteration. C++ became the language used when required, not the default choice.

The common perception in this period was that C++ was a legacy language. It was still essential for games, browsers, operating systems, and high-performance backends, but a lot of developers stopped paying attention to it. A stubborn version of this view still shows up in online debates, even though it's out of date.

The standard that shipped in 2011 changed that perception.

The Modern C++ Revolution: C++11

In September 2011, the ISO committee published C++11, originally known as C++0x. It was the biggest update to the language since C++98, and people had been waiting for it for over a decade. Stroustrup himself described C++11 as feeling "like a new language", and that line still gets quoted in talks today.

The short version of what C++11 added:

  • `auto` keyword for type deduction, removing the need to spell out long iterator types.
  • Range-based for loops (for (auto& item : cart)) for clean iteration.
  • Lambda expressions for inline, anonymous functions.
  • Smart pointers (std::unique_ptr, std::shared_ptr, std::weak_ptr) to manage memory without raw new and delete.
  • Move semantics and rvalue references (&&) to avoid copies of large objects.
  • `nullptr` as a typed replacement for the old NULL macro.
  • Uniform initialization with {} braces.
  • `override` and `final` keywords for safer inheritance.
  • `std::thread`, mutexes, futures, and atomics for built-in concurrency.
  • Variadic templates for templates that take any number of arguments.

Any one of these would have been a notable release. Together, they reshaped how everyday C++ code looks. Code written before C++11 is heavy on raw pointers, manual loops with verbose iterator types, and NULL. Code written after looks lighter.

The other big shift C++11 brought was cultural. The community started talking about "Modern C++" as a distinct style, one that uses the standard library, prefers smart pointers over raw new, and uses move semantics to write fast code without low-level tricks. The phrase "no naked new" became a common piece of advice. Style guides like the C++ Core Guidelines, edited by Stroustrup and Herb Sutter, codified this approach.

C++14 to C++23: The Three-Year Cadence

After C++11 shipped, the committee decided not to repeat the eight-year wait. They committed to a three-year release cadence: a new standard every three years, even if it was a smaller one. That rhythm has held since 2011.

The timeline below shows the milestones:

The diagram tracks the language from its prototype days through every ISO release. C++98 was the first standardized version, C++11 was the big reinvention, and everything after has come in three-year intervals.

C++14 (December 2014) was a small, polish-focused release. It added generic lambdas (auto parameters in lambda expressions), std::make_unique, return type deduction for regular functions, and binary literals like 0b1010. Nothing earth-shaking, but enough quality-of-life improvements that most teams who had jumped to C++11 upgraded.

C++17 (December 2017) brought more substantial features. Structured bindings unpack a std::pair or std::tuple into named variables in a single line. `if constexpr` allowed compile-time branching inside templates. `std::optional`, `std::variant`, and `std::any` filled long-standing gaps in the standard library. The `<filesystem>` library standardized file and directory operations, replacing decades of platform-specific code. `std::string_view` gives a cheap, non-owning view into a string.

C++20 (December 2020) was the next big leap, on the scale of C++11. The headline features:

  • Concepts, which write constraints on template parameters in plain language instead of relying on cryptic SFINAE tricks.
  • Ranges, a new way to compose operations on sequences (filter, transform, take) without explicit iterators.
  • Modules, a long-awaited replacement for the C-style #include system that should eventually make C++ builds faster.
  • Coroutines, language-level support for functions that can pause and resume, useful for async I/O and generators.
  • The three-way comparison operator (<=>, called the "spaceship operator") to auto-generate all six comparison operators from one definition.

C++20 also added smaller but high-impact features: consteval and constinit, designated initializers, calendar and time-zone support in <chrono>, and std::span for non-owning views into contiguous data.

C++23 (published in 2024 after final approval in late 2023) is the most recent standard. It's smaller than C++20 but still useful: `std::expected` for error handling without exceptions, `std::print` and `std::println` for cleaner output than std::cout, `std::flat_map` and `std::flat_set` as cache-friendly alternatives to the tree-based containers, multidimensional subscript operator (matrix[i, j]), and ranges improvements like views::zip and views::enumerate.

The same information as a table:

StandardYearSignature Features
C++981998First ISO standard, STL, exceptions, templates, namespaces
C++032003Bug-fix release, no new features
C++112011auto, lambdas, smart pointers, move semantics, range-for, threads
C++142014Generic lambdas, make_unique, binary literals
C++172017Structured bindings, if constexpr, optional, variant, filesystem
C++202020Concepts, ranges, modules, coroutines, spaceship operator
C++232023std::expected, std::print, flat containers, multidim subscript

The rows above cover the dates worth knowing.

Why the History Matters

The reasons to know this are practical, not academic.

Code from every era still lives in production. A C++ codebase often mixes styles. The core might be C++98 because it was written in 2005 and nobody wants to touch it. A new module might be C++20 because the team is using a current compiler. auto_ptr (removed in C++17) can sit next to std::unique_ptr (added in C++11) in the same file. Knowing which features came when helps when reading that code.

Compiler flags matter. Compilers default to a specific C++ standard, and that default has changed over time. GCC 11 defaults to C++17. GCC 13 defaults to C++17 by default but supports up to C++23 with the right flag. The -std=c++17 or -std=c++20 flag in a build script controls which features are available.

Job interviews ask about it. "What's the difference between C++98 and modern C++?" is a common opening question for senior C++ roles. So is "what version added nullptr?" or "when were lambdas introduced?". The answers are in the table above.

Library compatibility depends on it. A library that requires C++20 won't compile on a project frozen at C++14. Knowing which features came in which standard determines whether a dependency is realistic to adopt.

Stroustrup has said that one of his goals was for C++ to evolve without breaking old code. He's largely succeeded. A program written for C++98 will, with rare exceptions, still compile and run on a C++23 compiler. That backward compatibility is why so many systems written in the 1990s are still maintained in modern C++ rather than rewritten from scratch.

Quiz

History of C++ Quiz

7 quizzes