学现代 C++,最怕的不是语法多,而是 demo 跑不起来、编译器版本对不上、CMake 报错看不懂。这一篇我们不讲任何语言特性,只把「能编译、能运行、知道 41 个 demo 在哪」这件事搞定。后面 27 篇会在这个环境里,逐个拆解 C++11 到 C++23 的核心特性。

这是「现代 C++ 实战」系列的第 0 篇。本系列基于 ref/cpp_demo 的 41 个独立 CMake 项目,在 Docker 或 macOS 本地编译运行。下一篇我们从 CMake 与现代构建说起,搞懂 FetchContent 依赖管理。

一、为什么这样学?

你可能已经会写 C++,但面对 C++11 之后的「现代 C++」,往往有这样的困惑:特性太多、标准迭代太快、书和博客各说各话。本系列的选择很克制:

选择 原因
Demo 驱动 每个知识点对应可编译、可运行的代码,不是纸上谈兵
41 个独立项目 每个子目录自包含,可单独拷贝到其他机器
统一 build.sh 所有 demo 同一套构建命令,降低切换成本
Docker + macOS 双环境 容器(Ubuntu 26.04 + GCC 15/16 + Clang 22)保证 Linux 一致性,本地 Apple Clang 也支持
C++11→23 递进 按标准版本组织,不跳步

可以把它想成学开车:我们先找一条封闭赛道(统一工具链),车况一致(CMake 3.20+),专心练操作,而不是先纠结「我这辆车该加几号油」。

二、项目全景

示例代码在本地 ref/cpp_demo 目录(与博客同工作区)。9 大分类、41 个独立 CMake 项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ref/cpp_demo/
├── README.md # 总索引
├── Dockerfile # 开发镜像 cpp_demo:v2(Ubuntu 26.04)
├── setup_docker_deps.sh # 系统依赖唯一清单
├── run_as_cpp_docker.sh # 启动 / 构建 Docker 开发环境
├── scripts/ # build.sh 模板、同步脚本、一键全量编译
├── docs/CPP_IDE_SETUP.md # clangd 配置指南
├── basics/ # 23 个子项目:语言特性、设计模式、测试
├── smart_pointers/ # 9 个智能指针演示
├── concurrency/ # 线程、线程池、C++20 同步原语
├── algorithms/ # 7 类算法与数据结构
├── networking/ # HTTP+JSON、WebSocket(均基于 cpp-httplib)
├── database/ # SQLite3 CRUD
├── projects/ # 进阶项目 + FetchContent 示例
├── graphics/ # stb 单头文件库:图像读写、Perlin 噪声、TrueType
└── tvision/ # Turbo Vision 跨平台文本界面(TUI)示例

每个子目录都是独立自包含的项目,标准结构如下:

1
2
3
4
5
6
<项目目录>/
├── CMakeLists.txt # CMake 构建配置
├── build.sh # 跨平台构建脚本(macOS / Linux)
├── .gitignore # Git 忽略规则
├── README.md # 项目说明
└── src/ 或 *.cpp # 源代码

三、统一构建方式

所有 demo 遵循同一套构建命令,进入任意项目目录即可:

1
2
3
4
5
6
7
8
9
cd ref/cpp_demo/basics/lambda_demo   # 任选一个 demo
./build.sh # 增量编译
./build.sh -c # 清理后重新编译
./build.sh -d # Debug 模式
./build.sh -s --run # Debug + AddressSanitizer/UBSan 并运行
./build.sh --cxx clang++ # 指定编译器(容器内可选 g++-16、clang++)
./build.sh --run [target] # 编译后运行(全部或指定目标)
./build.sh --run-args "..." # 编译后运行并传参
./build.sh -h # 查看帮助

build.sh 会自动完成:创建 build/ 目录 → 运行 CMake 配置 → 并行编译 → 可选运行。首次编译时还会把 compile_commands.json 链接到项目根目录,方便 clangd 识别头文件。

几个值得知道的细节:

  • 自动适配环境切换:macOS 与 Docker 共用同一个 build/ 目录。build.sh 会记录「平台 / 路径 / 编译器」指纹,发现变化就自动重建,不会再遇到 CMakeCache.txt directory is different 这类缓存冲突。
  • 脚本由模板生成:所有 build.sh 都来自根目录的 scripts/build.sh.template,改完模板执行 scripts/sync_build_scripts.sh 同步;每个子项目仍然可以单独拷走使用。
  • 一键全量编译:scripts/build_all.sh 会依次编译全部子项目并汇总结果,适合升级编译器或依赖后做回归。

快速验证

选最简单的 demo 跑一遍,确认环境没问题:

1
2
cd ref/cpp_demo/basics/lambda_demo
./build.sh --run

这个 demo 只有一个带初始化捕获的 Lambda,计算 3 + 4 + 1 + 1。如果在 [SUCCESS] 编译完成! 之后看到程序输出 9,说明 CMake + 编译器链路已经通了。

四、Docker 环境

跨平台一致性靠 Docker。镜像 cpp_demo:v2 由仓库里的 Dockerfile 基于 ubuntu:26.04 构建,不依赖任何私有镜像:

类别 内容
编译器 GCC 15(默认)、GCC 16(g++-16,尝鲜 C++26)、Clang 22 + libc++
构建工具 CMake 4.2、Ninja、ccache
调试 / 分析 gdb、lldb、valgrind、clangd、clang-tidy、clang-format
项目依赖 SQLite3、OpenSSL、ncurses、TBB

系统依赖统一写在 setup_docker_deps.sh 里,它是唯一清单,Dockerfile 直接调用它,避免两处列表不一致。

启动方式:

1
2
3
4
5
cd ref/cpp_demo
./run_as_cpp_docker.sh # 进入容器 shell(镜像不存在时自动构建)
./run_as_cpp_docker.sh --build # 修改依赖后强制重建镜像
./run_as_cpp_docker.sh basics/span_demo/build.sh --run # 直接在容器中执行一条命令
./run_as_cpp_docker.sh scripts/build_all.sh # 在容器中编译全部项目

脚本会自动把仓库目录挂载到容器的 /workspace,并映射 8080 端口给网络类 demo 使用,无需手动改挂载路径。它还开启了 SYS_PTRACE,gdb / lldb / Sanitizer 在容器里都能正常工作。

镜像源:构建镜像时默认使用清华 apt 源。可以用环境变量切换,例如 APT_MIRROR=mirrors.aliyun.com ./run_as_cpp_docker.sh --build;设为空值 APT_MIRROR= 则使用 Ubuntu 官方源。

五、macOS 本地编译

不想开 Docker 也可以直接在 macOS 上编译。要求:

项目 说明
Apple Clang Xcode Command Line Tools,建议 14+
CMake 3.20 及以上
C++ 标准 各 demo 标注了所需标准(C++11 ~ C++23)

常见坑:

  • C++20/23 demo 编译失败:各 demo 的 CMakeLists.txt 已设置所需标准(并开启 CMAKE_CXX_STANDARD_REQUIRED),报错多半是 Clang 版本不够新;例如 basics/cpp23_features/ 需要 Apple Clang 16+
  • WebSocket demo:已改用 cpp-httplib 内置的 WebSocket 支持,通过 FetchContent 自动下载,不再需要安装 Boost
  • SQLite demo:依赖 sqlite3 开发库(CMake 先用 find_package(SQLite3),找不到再回退 pkg-config;macOS 系统自带即可)

大部分 basics/ 和 algorithms/ 下的 demo 在 macOS 上可以直接 ./build.sh --run,无需额外依赖。

六、IDE 配置速览

用 Cursor / VS Code 写 C++ 时,第三方库头文件可能报红(FetchContent 下载的依赖在 build/_deps/ 下)。解决办法:

  1. 先 ./build.sh 编译一次,生成 build/compile_commands.json
  2. build.sh 会自动链接到项目根目录
  3. clangd 读取该文件,获得正确的头文件搜索路径

详细步骤见 ref/cpp_demo/docs/CPP_IDE_SETUP.md。记住一点:IDE 报红不代表编译失败,以 ./build.sh 的结果为准。

七、28 篇学习路线

本系列共 28 篇,分五季发布:

季 篇号 主题 篇数
第零季 00–02 环境与基础 3
第一季 03–11 现代 C++ 核心特性 9
第二季 12–17 并发与工程实践 6
第三季 18–23 算法与数据结构 6
第四季 24–27 网络、数据库与进阶项目 4

前几篇的路线图:

篇号 标题 对应 demo
00 环境搭建与项目导览 本篇
01 CMake 与现代构建 projects/fetch_content/
02 C++ 版本演进一览 basics/version_features/
03 移动语义与右值引用 basics/right_ref_demo/
04 智能指针(上) smart_pointers/ 01–04
… … …

八、常用命令备忘

1
2
3
4
5
6
7
8
9
10
11
12
# 进入任意 demo 编译运行
cd ref/cpp_demo/<分类>/<项目>
./build.sh --run

# Docker 环境
cd ref/cpp_demo && ./run_as_cpp_docker.sh

# 用 Clang + Sanitizer 排查内存问题
./build.sh --cxx clang++ -s --run

# 清理重建
./build.sh -c && ./build.sh --run

九、小结

本篇完成了系列的地基:项目全景、统一构建、Docker / macOS 双环境、IDE 配置要点。你不需要记住 41 个 demo 的细节,只要确认 ./build.sh --run 能跑通一个 demo 就行。

现代 C++ 实战系列第 0 篇完。下一篇我们讲 CMake 与现代构建——搞懂 FetchContent,后面所有带第三方依赖的 demo 都不怕。