Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← C++ 编程 / C++ Programming

现代 C++ / Modern C++

1. 现代 C++ 总览:不是特性清单,而是表达能力 / Modern C++ Overview

2. 移动、转发与值类别:std::move 为什么不移动 / Move, Forward, and Value Categories

3. 类型推导、初始化与 constexpr / Type Deduction, Initialization, and constexpr

4. 模板、实例化与 SFINAE / Templates, Instantiation, and SFINAE

5. concept 与约束:把模板要求写在接口上 / Concepts and Constraints

6. 异常、RAII 与 noexcept:失败路径也要清理 / Exceptions, RAII, and noexcept

7. lambda、捕获与生命周期:回调不是免费午餐 / Lambdas, Captures, and Lifetime

8. callable wrapper 与 std::invoke:怎样保存和调用行为 / Callable Wrappers and std::invoke

9. 词汇类型与错误建模:让接口自己说话 / Vocabulary Types and Error Modeling

10. 协程与异步抽象:先理解状态机 / Coroutines and Async Abstractions

本页目录

现代 C++ 总览:不是特性清单,而是表达能力 / Modern C++ Overview ​

现代 C++ 不是把 auto、lambda、move、concept、coroutine 背一遍。

它真正改变的是:你能不能把程序里的所有权、类型关系、编译期约束、错误状态和异步流程表达得更清楚。

如果把现代 C++ 学成特性清单,会很快变成这样:

text
C++11: auto, lambda, move, unique_ptr
C++14: generic lambda
C++17: optional, variant, if constexpr
C++20: concept, ranges, coroutine
1
2
3
4

这张表有用,但不适合当学习主线。

因为写代码时你面对的问题通常不是:

text
我今天要用哪个新语法?
1

而是:

text
这个对象能不能被复制?
这个值能不能被移动?
这个类型是不是我以为的类型?
这个模板为什么报错这么长?
这个 lambda 捕获的对象还活着吗?
这个函数可能失败,接口应该怎么表达?
这个异步操作暂停后,局部状态保存在哪里?
1
2
3
4
5
6
7

现代 C++ 的学习主线应该围绕这些问题展开。

1. 现代 C++ 主要补强了什么 ​

可以先看这张图:

text
+--------------------------------------------------+
| async / control flow                             |
| coroutine, future-like abstractions              |
+--------------------------------------------------+
| error and state modeling                         |
| optional, variant, expected-style result         |
+--------------------------------------------------+
| callable abstraction                             |
| lambda, function object, std::function, invoke   |
+--------------------------------------------------+
| generic constraints                              |
| templates, SFINAE, concepts                      |
+--------------------------------------------------+
| compile-time reasoning                           |
| constexpr, if constexpr, type traits             |
+--------------------------------------------------+
| value and ownership movement                     |
| value category, move, forward, RAII              |
+--------------------------------------------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

底层仍然是前面模块学过的东西:

text
对象
引用
指针
函数
构造析构
作用域
生命周期
所有权
1
2
3
4
5
6
7
8

现代 C++ 不是替代这些基础。

它是在这些基础上增加更强的表达能力。

2. std::move 解决的是复制成本和所有权转移 ​

假设有一个很大的字符串或容器:

cpp
#include <string>

std::string make_text();

void consume(std::string text);
1
2
3
4
5

如果对象内部拥有一大块动态内存,复制它可能很贵。

移动语义允许对象把内部资源转交给另一个对象。

text
copy
  新对象得到一份独立内容
  可能需要重新分配和复制大量数据

move
  新对象接管旧对象内部资源
  旧对象仍然有效,但内容不应依赖
1
2
3
4
5
6
7

所以 std::move 不是“优化魔法”。

它和内存管理模块里的所有权直接相连。

3. auto 解决的是类型书写,不是不用理解类型 ​

auto 能减少重复:

cpp
std::vector<std::string>::iterator it = names.begin();
auto it2 = names.begin();
1
2

但 auto 不是让你不用理解类型。

它只是让编译器根据初始化表达式推导类型。

你仍然要知道:

text
auto 会不会丢掉引用?
auto 会不会丢掉顶层 const?
auto& 和 const auto& 有什么区别?
decltype(auto) 为什么更敏感?
1
2
3
4

现代 C++ 很多 bug 都来自“我以为推导出来的是 A,其实是 B”。

所以类型推导必须配合例子讲。

4. 模板和 concept 解决的是泛型边界 ​

模板让你写适用于多种类型的代码:

cpp
template <class T>
T max_value(T a, T b) {
    return a < b ? b : a;
}
1
2
3
4

但模板的问题是:如果类型不满足要求,错误信息可能很长。

concept 的方向是把要求写在接口上:

cpp
template <class T>
concept Addable = requires(T a, T b) {
    a + b;
};
1
2
3
4

它不是为了显得高级。

它是为了让泛型代码的边界更清楚:

text
这个模板需要什么能力?
不满足时,错误能不能尽早、清楚地报出来?
1
2

5. lambda 解决的是“把行为当对象传递” ​

函数可以传递行为:

cpp
bool less(int a, int b) {
    return a < b;
}
1
2
3

lambda 让你在需要的位置直接写一个小的可调用对象:

cpp
auto less = [](int a, int b) {
    return a < b;
};
1
2
3

但 lambda 的重点不是短。

重点是它可以捕获上下文:

cpp
int base = 10;
auto add_base = [base](int x) {
    return x + base;
};
1
2
3
4

捕获会引入生命周期问题。

如果你按引用捕获一个局部变量,然后 lambda 被保存到更远的地方,就可能悬垂。

所以 lambda 也必须和生命周期一起学。

6. optional、variant 解决的是状态表达 ​

老式代码可能用特殊值表示失败:

cpp
int find_user_id(); // 返回 -1 表示没找到
1

问题是:

text
-1 是有效业务值吗?
调用者会不会忘记检查?
失败原因能不能表达?
1
2
3

std::optional<int> 更清楚:

cpp
#include <optional>

std::optional<int> find_user_id();
1
2
3

它表达:

text
可能有 int
也可能没有值
1
2

variant 表达“几种类型之一”。

这些类型不是为了炫技,而是让状态进入类型系统。

7. coroutine 解决的是异步状态机表达 ​

协程看起来像新语法:

cpp
co_await something;
1

但它背后的问题是:

text
一个函数执行到一半暂停后,局部状态放在哪里?
异步完成后,怎样恢复执行?
错误怎样传播?
谁拥有协程帧?
1
2
3
4

所以协程不能只讲关键字。

要先讲状态机。

text
start
  |
  v
run until await
  |
  v
save state
  |
  v
suspend
  |
  v
resume later
  |
  v
continue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

8. 本模块阅读路线 ​

建议顺序:

text
00 总览
  |
  v
01 移动、转发和值类别
  |
  v
02 类型推导、初始化与 constexpr
  |
  v
03 模板、实例化与 SFINAE
  |
  v
04 concepts 与约束
  |
  v
05 异常、RAII 与 noexcept
  |
  v
06 lambda、捕获与生命周期
  |
  v
07 callable wrappers 与 invoke
  |
  v
08 vocabulary types 与错误建模
  |
  v
09 coroutine 与异步抽象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

这不是按标准版本排序。

而是按理解依赖排序。

你先要懂值类别和类型推导。

再去看模板和约束。

最后再看 lambda 保存状态、错误建模和协程。

9. 和前面模块的关系 ​

现代 C++ 依赖前面三个模块:

text
01-language-basics
  名字、类型、表达式、函数、引用、指针、编译链接

02-object-oriented-programming
  对象模型、构造析构、继承、多态、接口设计

03-memory-management
  生命周期、所有权、RAII、智能指针、容器内存

04-modern-cpp
  用更精确的语言机制表达上面这些边界
1
2
3
4
5
6
7
8
9
10
11

如果引用没学清楚,std::forward 会很难。

如果生命周期没学清楚,lambda 捕获会很危险。

如果 RAII 没学清楚,异常和 noexcept 会变成空话。

10. 本篇总结 ​

现代 C++ 的价值可以概括为:

text
让值移动得更清楚
让类型推导得更可控
让编译期能做更多检查
让泛型接口能表达约束
让资源清理和错误传播更稳
让行为和异步状态能被对象化
1
2
3
4
5
6

本模块不追求“每个新特性都介绍一遍”。

它追求的是:你看到现代 C++ 代码时,能判断这段语法背后在表达什么边界。

最后更新于:

Pager
上一篇← C++ 编程 / C++ Programming
下一篇2. 移动、转发与值类别:std::move 为什么不移动 / Move, Forward, and Value Categories

持续记录,持续成长

Copyright © Tidenflow