Modern C++ & STL Essentials
RAII and smart pointers, containers and their complexity trade-offs, iterators and algorithms, move semantics, and templates.
RAII and Smart Pointers
// RAII:资源获取即初始化,构造获取、析构释放
// 离开作用域自动销毁 —— 无需手动 delete
#include <memory>
void f() {
// 独占所有权(不可拷贝,可移动)
auto p = std::make_unique<Order>(42);
p->charge();
// 共享所有权(引用计数)
auto shared = std::make_shared<Config>();
auto s2 = shared; // 计数 = 2
// 弱引用:不增加计数,防循环引用
std::weak_ptr<Node> weak = shared;
if (auto sp = weak.lock()) { /* 对象仍存活 */ }
} // p、shared 在此自动释放
Rule of thumb: default to unique_ptr; use shared_ptr only when ownership is genuinely shared; never use raw new/delete or bare owning pointers in modern code.
Containers: Pick by Complexity
| 容器 | 查找 | 插入/删除 | 典型用途 |
|---|---|---|---|
| vector | O(n) | 尾部 O(1) 摊销 | 默认容器:随机访问、缓存友好 |
| deque | O(n) | 首尾 O(1) | 队列、滑动窗口 |
| list | O(n) | 已知位置 O(1) | 频繁中间插删(少见) |
| unordered_map/set | 平均 O(1) | 平均 O(1) | 键值缓存、去重 |
| map/set | O(log n) | O(log n) | 需要有序遍历 |
| array | O(n) | 不可变 | 固定大小、零开销 |
std::vector<int> v{3, 1, 4, 1, 5};
v.push_back(9); // 尾部追加
v.shrink_to_fit(); // 回收多余容量
std::unordered_map<std::string, int> stock;
stock["apple"] = 12;
// 结构化绑定遍历(C++17)
for (const auto& [sku, qty] : stock) {
std::cout << sku << ':' << qty << '\n';
}
// span:不拷贝的只读视图(C++20),替代 (ptr, size) 接口
void top(std::span<const int> nums);
vector plus sorting beats a linked list almost always: contiguous memory keeps CPU caches happy. Know the element count in advance? Use reserve() to avoid reallocation copies.
Algorithms and Lambda
#include <algorithm>
std::vector<Order> orders = load();
// 按金额排序(lambda 比较器)
std::ranges::sort(orders, {}, &Order::amount); // C++20 ranges
// 过滤 + 变换
auto big = orders | std::views::filter([](auto& o) { return o.amount > 100; })
| std::views::transform(&Order::id);
// 计数/查找
auto n = std::ranges::count_if(orders, &Order::is_paid);
auto it = std::ranges::find(orders, 42, &Order::id);
// 拷贝到新容器
std::vector<Order> paid;
std::ranges::copy_if(orders, std::back_inserter(paid), &Order::is_paid);
Move Semantics and Templates
// 移动:转移资源所有权,不拷贝
std::vector<Order> v2 = std::move(v1); // v1 变为有效空状态
// 按值传参 + std::move 进容器:最高效
void add(std::vector<Order>& out, Order o) {
out.push_back(std::move(o)); // 局部对象直接移动
}
// 函数模板:鸭子类型,编译期生成
template <typename T>
T sum(const std::vector<T>& xs) {
T total{}; // 值初始化
for (const auto& x : xs) total += x;
return total;
}
// 概念(C++20):约束模板参数,报错更可读
template <std::totally_ordered T>
T max_of(T a, T b) { return a > b ? a : b; }
Do not std::move a return value (return value is already treated as an rvalue) and do not move from an object you keep using — it is valid but unspecified.
RAII 与智能指针
// RAII:资源获取即初始化,构造获取、析构释放
// 离开作用域自动销毁 —— 无需手动 delete
#include <memory>
void f() {
// 独占所有权(不可拷贝,可移动)
auto p = std::make_unique<Order>(42);
p->charge();
// 共享所有权(引用计数)
auto shared = std::make_shared<Config>();
auto s2 = shared; // 计数 = 2
// 弱引用:不增加计数,防循环引用
std::weak_ptr<Node> weak = shared;
if (auto sp = weak.lock()) { /* 对象仍存活 */ }
} // p、shared 在此自动释放
经验法则:默认 unique_ptr;确有多方持有才用 shared_ptr;现代代码里不要再写裸 new/delete。
容器:按复杂度选型
| 容器 | 查找 | 插入/删除 | 典型用途 |
|---|---|---|---|
| vector | O(n) | 尾部 O(1) 摊销 | 默认容器:随机访问、缓存友好 |
| deque | O(n) | 首尾 O(1) | 队列、滑动窗口 |
| list | O(n) | 已知位置 O(1) | 频繁中间插删(少见) |
| unordered_map/set | 平均 O(1) | 平均 O(1) | 键值缓存、去重 |
| map/set | O(log n) | O(log n) | 需要有序遍历 |
| array | O(n) | 不可变 | 固定大小、零开销 |
std::vector<int> v{3, 1, 4, 1, 5};
v.push_back(9); // 尾部追加
v.shrink_to_fit(); // 回收多余容量
std::unordered_map<std::string, int> stock;
stock["apple"] = 12;
// 结构化绑定遍历(C++17)
for (const auto& [sku, qty] : stock) {
std::cout << sku << ':' << qty << '\n';
}
// span:不拷贝的只读视图(C++20),替代 (ptr, size) 接口
void top(std::span<const int> nums);
vector 加排序几乎总能赢过链表:连续内存对 CPU 缓存友好。能预估数量就先 reserve(),避免扩容拷贝。
算法与 lambda
#include <algorithm>
std::vector<Order> orders = load();
// 按金额排序(lambda 比较器)
std::ranges::sort(orders, {}, &Order::amount); // C++20 ranges
// 过滤 + 变换
auto big = orders | std::views::filter([](auto& o) { return o.amount > 100; })
| std::views::transform(&Order::id);
// 计数/查找
auto n = std::ranges::count_if(orders, &Order::is_paid);
auto it = std::ranges::find(orders, 42, &Order::id);
// 拷贝到新容器
std::vector<Order> paid;
std::ranges::copy_if(orders, std::back_inserter(paid), &Order::is_paid);
移动语义与模板
// 移动:转移资源所有权,不拷贝
std::vector<Order> v2 = std::move(v1); // v1 变为有效空状态
// 按值传参 + std::move 进容器:最高效
void add(std::vector<Order>& out, Order o) {
out.push_back(std::move(o)); // 局部对象直接移动
}
// 函数模板:鸭子类型,编译期生成
template <typename T>
T sum(const std::vector<T>& xs) {
T total{}; // 值初始化
for (const auto& x : xs) total += x;
return total;
}
// 概念(C++20):约束模板参数,报错更可读
template <std::totally_ordered T>
T max_of(T a, T b) { return a > b ? a : b; }
不要对返回值 std::move(返回值本身就是右值);也不要移动之后继续使用原对象——状态合法但未定义。