“C++ Primer, Fifth Edition” is a classic textbook in the field of C++, comprehensively covering the core features of the C++11 standard, balancing syntax details with programming practices, making it suitable for both beginners and experienced developers looking to fill gaps in their knowledge.Below, we extract the core knowledge points of the book from four dimensions: basic concepts, core features, containers and algorithms, advanced topics . Detailed explanations will follow later.Table of ContentsChapter 1: Getting StartedChapter 2: Variables and Basic TypesChapter 3: Strings, Vectors, ArraysChapter 4: ExpressionsChapter 5: StatementsChapter 6: FunctionsChapter 7: ClassesChapter 8: IO LibraryChapter 9: Sequence ContainersChapter 10: Generic AlgorithmsChapter 11: Associative ContainersChapter 12: Dynamic MemoryChapter 13: Copy ControlChapter 14: Overloaded Operators and Type ConversionsChapter 15: Object-Oriented Programming Overview, virtual functions, abstract base classes, access control and inheritance, the role of classes in inheritance, constructors and copy control, containers and inheritance, revisiting text query programsChapter 16: Templates and Generic Programming Definition of templates, template argument deduction, overloading and templates, variadic templatesChapter 17: Special Facilities of the Standard Library tuple type, bitset type, regular expressions, random numbers, revisiting the IO library.Chapter 18: Tools for Large Programs Exception handling, namespaces, multiple inheritance and virtual inheritance.Chapter 19: Special Tools and TechniquesAppendix A: Standard LibraryC++11 New Features Brief summary of the main content:
1. Basic Concepts and Syntax
This section is the “foundation” of C++, covering core syntax such as program structure, data types, expressions, and statements, which are the basis for further learning.
1. Program Structure and Basic Syntax
- Program Entry The entry point of all C++ programs is the
<span>main()</span>function, which must return an<span>int</span>(returning 0 indicates normal termination, non-zero indicates an error state). - Header Files and Namespaces
- Standard library header files do not have a
<span>.h</span>suffix (e.g.,<span><iostream></span>instead of<span><iostream.h></span>), while non-standard library header files may have a suffix. <span>std</span>is the namespace for the C++ standard library, and using standard library components requires explicit declaration:<span>using namespace std;</span>(for global use) or<span>std::cout</span>(for local qualification) to avoid naming conflicts.- Input and Output
- The standard input stream is
<span>cin</span>(used with<span>>></span>), the standard output stream is<span>cout</span>(used with<span><<</span>), and the standard error stream is<span>cerr</span>(used for outputting error messages, unbuffered), defined in<span><iostream></span>.
2. Data Types and Variables
C++ data types are divided into basic types and composite types, with the core understanding being the “meaning of types (memory usage, value range)” and “the lifecycle of variables”.
(1) Basic Types
| Type Category | Specific Type | Core Explanation |
|---|---|---|
| Boolean | <span>bool</span> |
Values can only be <span>true</span> (1) or <span>false</span> (0), occupying 1 byte. |
| Character | <span>char</span>/<span>wchar_t</span>/<span>char16_t</span> |
<span>char</span> occupies 1 byte (distinguishing <span>signed char</span>/<span>unsigned char</span>), while the latter two are used for wide characters. |
| Integer | <span>short</span>/<span>int</span>/<span>long</span>/<span>long long</span> |
Size relationship: <span>short</span> ≤ <span>int</span> ≤ <span>long</span> ≤ <span>long long</span>, <span>int</span> is usually 4 bytes, while <span>long long</span> is 8 bytes. |
| Floating Point | <span>float</span>/<span>double</span>/<span>long double</span> |
<span>float</span> (4 bytes, precision 6-7 digits), <span>double</span> (8 bytes, precision 15-17 digits), prefer using <span>double</span>. |
(2) Composite Types
- Reference (&) A variable’s “alias”, must be initialized and cannot be changed after binding, commonly used for function parameters (to avoid copying) and return values (to return objects instead of copies). Example:
<span>int a = 10; int &ref = a; ref = 20; // a's value becomes 20</span>. - Pointer (*) A variable that stores the address of another variable, can be null (
<span>nullptr</span>, added in C++11, replaces<span>NULL</span>), can point to different objects, and must be cautious of risks like “null pointer” and “dangling pointer” (uninitialized / pointing to released memory). Example:<span>int a = 10; int *p = &a; *p = 20; // a's value becomes 20</span>. - const Qualifier Modifies a variable to be “read-only”, must be initialized; when modifying a pointer, it is necessary to distinguish between “the pointer itself cannot change” (
<span>int *const p</span>) and “the pointed content cannot change” (<span>const int *p</span>). The core principle is that<span>const</span>modifies “the nearest variable or pointer on its right”.
3. Expressions and Statements
- Operator Precedence Arithmetic operators (
<span>*</span>/<span>/</span>take precedence over<span>+</span>/<span>-</span>) > relational operators (<span>></span>/<span><</span>) > logical operators (<span>&&</span>take precedence over<span>||</span>) > assignment operators (<span>=</span>), use parentheses when uncertain. - Increment / Decrement Operators
<span>++i</span>(prefix, increments before use) is more efficient than<span>i++</span>(postfix, uses before incrementing) (avoids temporary variables), especially prefer prefix in loops or container iterations. - Conditional Statements and Loops
- Conditional statements:
<span>if-else</span>(supports initialization statements, such as<span>if (int a = 10; a > 5)</span>),<span>switch</span>(case must include<span>break</span>, otherwise it will “fall through”, supports<span>string</span>and enumeration types). - Loop statements:
<span>for</span>(C++11 supports “range for”,<span>for (auto x : container)</span>),<span>while</span>,<span>do-while</span>(executes at least once).
2. Core Features of C++11 (Key Points)
1. Automatic Type Deduction (auto)
Function: Allows the compiler to automatically deduce the variable type based on the initialization value, simplifying code (especially when dealing with complex types like iterators, container element types). Rules:
- Must be initialized (otherwise type cannot be deduced).
- When deducing references, must explicitly add
<span>&</span>(e.g.,<span>auto &x = a</span>, deduced as reference type). - When deducing
<span>const</span>, if the variable is copy-initialized (e.g.,<span>auto x = const_a</span>),<span>const</span>will be lost; if it is reference-initialized (<span>auto &x = const_a</span>),<span>const</span>will be retained.
Example:
vector<int> vec = {1,2,3}; auto it = vec.begin(); // it type is vector<int>::iterator.
2. List Initialization ({})
- Function: Unifies initialization syntax, supports all types (basic types, arrays, containers, class objects), and can avoid “narrowing conversions” (e.g.,
<span>int a = {3.14}</span>will compile error, while<span>int a = 3.14</span>only warns). - Scenarios:
- Variable initialization:
<span>int a{10}; double b{3.14};</span>. - Container initialization:
<span>vector<int> vec{1,2,3}; map<string, int> mp{{"a",1}, {"b",2}};</span>. - Class object initialization:
<span>class A { int x; }; A a{5};</span>(class must support aggregate initialization or have a matching constructor).
3. Range for Loop
- Syntax:
<span>for (declaration : sequence)</span>, iterates over each element of the sequence (arrays, containers, initializer lists, etc.), without manually managing indices or iterators. - Note:
- If modification of elements is needed,
<span>declaration</span>must be a reference (<span>auto &x</span>); if read-only, can use<span>const auto &x</span>(to avoid copying, efficient). - The sequence must be iterable (i.e., has
<span>begin()</span>and<span>end()</span>members, or can be processed by the standard library<span>begin()</span>/<span>end()</span>functions). - Example:
<span>vector<int> vec{1,2,3}; for (auto &x : vec) x *= 2; // vec becomes {2,4,6}</span>.
4. Smart Pointers (RAII Mechanism)
C++11 introduces smart pointers to solve the problem of “manually managing dynamic memory leading to memory leaks and dangling pointers”, with the core being RAII (Resource Acquisition Is Initialization): binding resources (like dynamic memory) to the object lifecycle, automatically releasing resources when the object is destroyed.
The three types of smart pointers are defined in <span><memory></span>, with the following comparisons:
| Smart Pointer Type | Core Functionality | Usage Scenarios | Notes |
|---|---|---|---|
<span>unique_ptr</span> |
Exclusive ownership, only one <span>unique_ptr</span> can point to an object at a time, cannot be copied (can be moved). |
Manage a single dynamic object without needing shared ownership. | Cannot use <span>operator=</span> for copying, must use <span>std::move()</span> to transfer ownership; for arrays, must explicitly specify <span>unique_ptr<T[]></span>. |
<span>shared_ptr</span> |
Shared ownership, multiple <span>shared_ptr</span> can point to the same object, internally maintains a “reference count”, releasing the object when the count reaches 0. |
Need to share object ownership (e.g., storing pointers in containers, sharing objects in multithreading). | Avoid “circular references” (e.g., two <span>shared_ptr</span> pointing to each other, causing the count to never reach zero, leading to memory leaks), must use <span>weak_ptr</span> to resolve. |
<span>weak_ptr</span> |
Weak reference, points to an object managed by <span>shared_ptr</span>, but does not increase the reference count, can check if the object is alive. |
Solves the circular reference problem of <span>shared_ptr</span>. |
Cannot directly access the object, must use <span>lock()</span> to obtain a <span>shared_ptr</span> (if the object is alive, returns a valid <span>shared_ptr</span>, otherwise returns null). |
Example (<span>unique_ptr</span>):
unique_ptr<int> up(new int(10)); // exclusively manages dynamic intunique_ptr<int> up2 = move(up); // transfer ownership, up becomes null// no need for manual delete, memory is automatically released when up2 is destroyed
5. Rvalue References and Move Semantics (&&)
C++11 introduces “rvalue references” to solve the problem of “copying large amounts of data leading to performance waste”, with the core being the distinction between “lvalues” (objects that can be addressed and have names, such as variable <span>a</span>) and “rvalues” (temporary objects that cannot be addressed, such as literals <span>10</span>, temporary objects returned from functions).
- Rvalue Reference (&&) can only bind to rvalues, used to “steal” resources from rvalues (instead of copying), implementing “move semantics”.
- Move Constructor / Move Assignment Operator
- When initializing an object with an rvalue, the compiler prioritizes calling the move constructor (instead of the copy constructor), directly “taking over” the memory of the rvalue, avoiding copying.
- If the class does not define move operations, the compiler will use copy operations instead.
- Example (move semantics):
vector<int> func() { return vector<int>{1,2,3}; } // returns a temporary object (rvalue)
vectort<int> vec1 = func(); // calls move constructor, steals memory from temporary object, no copy
vector<int> vec2 = move(vec1); // forces vec1 (lvalue) to become an rvalue, calls move constructor, vec1 becomes null
3. Containers and Algorithms (Core of STL)
The “container – iterator – algorithm” model of the C++ Standard Library (STL) is the essence of C++, and “C++ Primer” dedicates a large portion to explaining its usage and principles.
1. Container Classification and Features
STL containers are divided into sequence containers (store elements in order, with positional relationships) and associative containers (store by key, supporting fast lookups), along with container adapters (encapsulating other containers, providing simpler interfaces).
(1) Sequence Containers (defined in <span><vector></span>/<span><list></span>/<span><deque></span> and other headers)
| Container Type | Underlying Implementation | Core Advantages | Core Disadvantages | Applicable Scenarios |
|---|---|---|---|---|
<span>vector</span> |
Dynamic array | Random access (<span>[]</span> or <span>at()</span>) is efficient (O(1)), appending/removing from the end is efficient (O(1)). |
Inserting/removing from the middle is inefficient (O(n), requires moving elements), resizing may copy data. | Scenarios requiring frequent random access, appending, and few insertions/deletions (e.g., storing list data, buffers). |
<span>list</span> |
Doubly linked list | Efficient insertion/deletion at any position (O(1)), memory is non-contiguous, no need for resizing. | Does not support random access (only iteratively traversable, O(n)), each element requires additional pointer storage, leading to high memory overhead. | Scenarios requiring frequent insertions/deletions without random access (e.g., implementing linked lists, queues). |
<span>deque</span> |
Segmented dynamic array | Efficient insertion/deletion at both ends (O(1)), supports random access (O(1)). | Inserting/removing from the middle is inefficient (O(n)), random access efficiency is slightly lower than <span>vector</span>. |
Scenarios requiring operations at both ends and random access (e.g., implementing stacks, queues as underlying containers). |
<span>array</span> |
Fixed-size array | Stored on the stack, memory efficient, random access O(1), size determined at compile time. | Size is immutable, cannot dynamically resize. | Storing fixed-size data (e.g., storing 3 coordinate values <span>array<int,3></span><code><span>).</span> |
(2) Associative Containers (defined in <span><map></span>/<span><set></span> and other headers)
Associative containers are divided into ordered (implemented based on red-black trees, automatically sorted by key, lookup O(log n)) and unordered (implemented based on hash tables, average lookup O(1)).
| Container Type | Key-Value Relationship | Ordered / Unordered | Core Features |
|---|---|---|---|
<span>set</span> |
Stores only keys (keys are unique) | Ordered | Automatically sorts keys in ascending order, keys cannot be repeated, efficient for checking the existence of a key. |
<span>multiset</span> |
Stores only keys (keys can be repeated) | Ordered | Similar to <span>set</span>, but keys can be repeated, suitable for storing ordered data with duplicates (e.g., counting occurrences of grades). |
<span>map</span> |
Key-Value pairs (keys are unique) | Ordered | Automatically sorts keys in ascending order, keys cannot be repeated, allows fast lookup of values by key (<span>map[key]</span> or <span>find()</span>). |
<span>multimap</span> |
Key-Value pairs (keys can be repeated) | Ordered | Similar to <span>map</span>, but keys can be repeated, suitable for storing one-to-many mappings (e.g., one key corresponding to multiple values). |
<span>unordered_set</span> |
Stores only keys (keys are unique) | Unordered | Implemented using hash tables, faster lookup speed (average O(1)), keys are unordered, does not support sorting by key. |
<span>unordered_map</span> |
Key-Value pairs (keys are unique) | Unordered | Implemented using hash tables, suitable for high-frequency lookup scenarios (e.g., caching, dictionaries), keys are unordered. |
(3) Container Adapters
<span>stack</span>Stack (LIFO, last in first out), implemented based on<span>deque</span>by default, supports<span>push()</span>(push onto stack),<span>pop()</span>(pop from stack),<span>top()</span>(get top of stack).<span>queue</span>Queue (FIFO, first in first out), implemented based on<span>deque</span>by default, supports<span>push()</span>(enqueue),<span>pop()</span>(dequeue),<span>front()</span>(get front of queue).<span>priority_queue</span>Priority queue (default max heap), implemented based on<span>vector</span>by default, supports<span>push()</span>(insert),<span>pop()</span>(remove top of heap),<span>top()</span>(get top of heap).
2. Iterators
Iterators are the “bridge connecting containers and algorithms”, behaving like pointers, used to traverse container elements, with different containers having different iterator functionalities, divided into 5 types (from weak to strong):
- Input Iterator only supports reading, ++ (one-way), such as
<span>istream_iterator</span>. - Output Iterator only supports writing, ++ (one-way), such as
<span>ostream_iterator</span>. - Forward Iterator supports reading, writing, ++ (one-way), such as
<span>forward_list</span>‘s iterator. - Bidirectional Iterator supports reading, writing, ++/– (two-way), such as
<span>list</span>,<span>map</span>‘s iterator. - Random Access Iterator supports reading, writing, ++/–, random access (
<span>+n</span>/<span>-n</span>/<span>[]</span>), such as<span>vector</span>,<span>deque</span>,<span>array</span>‘s iterator.
Core Operations:
<span>*it</span>accesses the element pointed to by the iterator.<span>it-></span>accesses the member of the object pointed to by the iterator (e.g., the iterator of<span>map</span>points to<span>pair</span>,<span>it->first</span>gets the key).<span>++it</span>moves the iterator forward (prefer using prefix).<span>it1 == it2</span>checks if two iterators point to the same position.
Note: The <span>erase()</span> operation of the container will invalidate iterators pointing to deleted elements, and the iterator must be updated using the return value of <span>erase()</span> (pointing to the next element after the deleted one) to avoid dangling pointers.
3. Algorithms (STL Algorithm Library)
STL algorithms are defined in <span><algorithm></span>, divided into non-modifying algorithms (do not change container elements, such as searching, counting) and modifying algorithms (change container elements, such as sorting, copying, replacing), all operating on containers through iterators, regardless of container type.
Common algorithm examples:
- Search
<span>find(beg, end, val)</span><span> (searches for </span><code><span>val</span>in<span>[beg,end)</span><span>, returns an iterator, returns </span><code><span>end</span>if not found),<span>count(beg, end, val)</span>(counts the occurrences of<span>val</span>). - Sort
<span>sort(beg, end)</span><code><span> (default ascending sort, requires random access iterators, such as </span><code><span>vector</span>),<span>stable_sort(beg, end)</span>(stable sort, maintains the relative position of equal elements). - Copy
<span>copy(beg_in, end_in, beg_out)</span><span> (copies elements from </span><code><span>[beg_in,end_in)</span><span> to the position starting at </span><code><span>beg_out</span>, ensure target space is sufficient). - Replace
<span>replace(beg, end, old_val, new_val)</span><span> (replaces all </span><code><span>old_val</span>in<span>[beg,end)</span><span> with </span><code><span>new_val</span>). - Accumulate
<span>accumulate(beg, end, init)</span><span> (accumulates elements from </span><code><span>init</span>, starting from<span>[beg,end)</span><span>, defined in </span><code><span><numeric></span>).
4. Advanced Topics
1. Functions and Function Templates
- Function Parameters support default parameters (default parameters must be defined from right to left, such as
<span>void func(int a, int b=10)</span>), variadic parameters (C++11’s<span>initializer_list<T></span>, used to receive any number of parameters of the same type, such as<span>void func(initializer_list<int> args)</span>). - Function Overloading In the same scope, functions with the same name but different parameter lists (number, type, order) are matched by the compiler based on actual parameters; differing return types do not constitute overloading.
- Function Templates Define generic functions, the compiler automatically generates specific versions based on actual parameter types (template instantiation), syntax:
<span>template <typename T> T add(T a, T b) { return a + b; }</span>, supports template specialization (custom implementation for specific types).
2. Classes and Objects
- Basic Members of Classes Member variables (can add
<span>public</span>/<span>private</span>/<span>protected</span>access control, default is<span>private</span>), member functions (regular member functions, constructors, destructors, static member functions). - Constructors are used to initialize objects, have no return value, and share the same name as the class; support overloading, default constructors (no parameters or all parameters have default values, if the user defines other constructors, the compiler will not generate a default constructor), copy constructors (initialize a new object with an object of the same type, default shallow copy, if there is dynamic memory, a custom deep copy is required).
- Destructors are used to release object resources (such as dynamic memory, file handles), have no parameters, no return value, share the same name as the class with a
<span>~</span>, only one; if the class has dynamic memory, a custom destructor must be defined to avoid memory leaks. - Static Members are modified with
<span>static</span>, belong to the class rather than the object, shared by all objects; static member variables must be initialized outside the class, static member functions do not have a<span>this</span>pointer, cannot access non-static members.
3. Inheritance and Polymorphism
- Inheritance The subclass (derived class) inherits members from the parent class (base class), syntax:
<span>class Derived : public Base { ... }</span>; access control:<span>public</span>inheritance (base class<span>public</span>members become<span>public</span>in the subclass,<span>protected</span>becomes<span>protected</span>),<span>private</span>inheritance (base class members become<span>private</span>in the subclass),<span>protected</span>inheritance (base class<span>public</span>/<span>protected</span>members become<span>protected</span>in the subclass). - Polymorphism is achieved through “virtual functions”, where the base class declares a virtual function (
<span>virtual void func()</span>), and the subclass overrides it (<span>override</span>, a C++11 keyword, explicitly declares the override to avoid errors), when called through a base class pointer/reference, the corresponding version of the function is called based on the actual type of the object. - Abstract Classes are classes that contain pure virtual functions (
<span>virtual void func() = 0</span>), cannot be instantiated, can only serve as base classes, and subclasses must override pure virtual functions to be instantiated.
4. Exception Handling
- Syntax:
<span>try</span>(wraps code that may throw exceptions),<span>throw</span>(throws exceptions, can throw any type),<span>catch</span>(catches exceptions, matches by type,<span>...</span>catches all types of exceptions). - Principle: Exceptions are used to handle “exceptional situations” (such as file opening failures, memory allocation failures), not for normal logic checks; thrown exceptions should be catchable, otherwise the program terminates; the C++ standard library defines standard exception classes (such as
<span>std::runtime_error</span>,<span>std::out_of_range</span>), custom exception classes can inherit from standard exceptions.