Modern Cpp
This was migrated from version 1.0 and polished and expanded by Gemini.
Modern C++ Overview: From Low-Level Logic to Syntax Sugar
Preface: Encountered Modern C++ in a programming lab and could not defeat it with pure effort? After getting used to Java’s automatic memory management and Python’s flexibility, C++ syntax rules do look complicated, even a little strange.
Stereotypes about C++:
- Old, out-dated, less-frequently used
- Unsafe (the biggest pain point: memory leaks and out-of-bounds access)
- Hard to use & Various Compilation Issues
Even so, we still need to learn Modern C++, because it remains irreplaceable in systems programming and high-performance computing.
1. Value Types & Move Semantics
lvalue vs rvalue
- lvalue: An object that occupies an identifiable location in memory, namely an address. You can take its address with
&. - rvalue: Usually a temporary object. You cannot take its address with
&.
Copy Assignment vs Move Assignment
For an assignment operation a = xxx:
- Copy Assignment: Called when
xxxis an lvalue. - Move Assignment: Called when
xxxis an rvalue.
std::move
A common rule of thumb: Move is faster than copy. What if we want to move from an lvalue?
We can use std::move. It makes the compiler treat an lvalue as an rvalue, enabling ownership transfer.
Note: After using
std::move, the moved-from object should not be used in a meaningful way. Also,constvariables cannot use move semantics effectively.
Common Cases Where std::move Should Not Be Used
1 | void Print(const std::string &s); |
2. Type Inference & std::forward
Universal Reference
In templates, T&& does not always mean an rvalue reference. It can be a universal reference, accepting both lvalues and rvalues.
1 | template<typename T> |
3. Smart Pointers
Modern C++ uses smart pointers to manage memory and follows RAII, helping us move away from raw pointers.
std::unique_ptr
Core property: exclusive ownership. It cannot be copied, only moved.
Usage: create it with std::make_unique<T>(...).
std::shared_ptr
Core property: multiple owners can share the same resource.
Reference counting: a control block records how many pointers currently point to the object. When the count reaches zero, the object is automatically freed.
std::weak_ptr
This solves circular references. If A points to B and B also points to A, both as shared_ptr, they form a cycle and leak. weak_ptr does not increase the reference count. It can observe an object without extending its lifetime.
1 | struct Node { |
4. Syntax Sugar
auto Inference
auto automatically deduces variable types, making code cleaner, especially with iterators or complex templates.
1 | std::vector<int> vec = {1, 2, 3}; |
Structured Bindings - C++17
Extract multiple variables from std::pair or std::tuple at once.
1 | std::map<std::string, int> scores = {{"Alice", 90}}; |
5. Safety: C++17 Safe Containers
These help avoid unsafe union usage or error-prone null pointers.
std::any
Stores a value of any type, but access must go through any_cast for type-safe checking.
std::optional
Represents a value that may be empty. You no longer need to return -1 or nullptr to express “invalid”.
1 | std::optional<int> getValue(bool success) { |
std::variant
A type-safe union. It knows which type it currently stores and can be handled elegantly with std::visit.
1 | using MyType = std::variant<int, std::string>; |





