一篇由浅入深、涵盖概念、原理、源码与实战的对比与学习指南。
目录
一、基本概念
1.1 C++ 是什么
C++ 是一种多范式、编译型系统编程语言,由 Bjarne Stroustrup 在 1979 年起在 C 语言基础上扩展而来。特点包括:
- 零成本抽象:高级抽象(类、模板、智能指针)在合理使用下不增加运行时开销。
- 手动内存管理:可显式
new/delete,也可借助 RAII 与智能指针自动化。 - 多范式:面向过程、面向对象、泛型、函数式、元编程均可。
- 标准与生态:ISO 标准驱动,STL 与第三方库丰富,广泛应用于操作系统、游戏、嵌入式、高性能服务等。
1.2 Rust 是什么
Rust 是一种系统级、内存安全、无数据竞争的编程语言,由 Mozilla 发起,2015 年 1.0 稳定。特点包括:
- 所有权系统:通过所有权、借用、生命周期在编译期消除大部分内存错误与数据竞争。
- 无垃圾回收:不依赖 GC,通过类型系统与借用检查实现安全与性能兼得。
- 无畏并发:类型系统保证线程安全,避免数据竞争在编译期被发现。
- 现代工具链:
cargo包管理、rustfmt/clippy格式化与静态检查,体验统一。
1.3 定位对比(一句话)
| 维度 | C++ | Rust |
|---|---|---|
| 设计目标 | 性能 + 灵活 + 与 C 兼容 | 安全 + 性能 + 并发 + 现代工具链 |
| 内存安全 | 需开发者自律与规范 | 编译器强制保证(所有权/借用) |
| 学习曲线 | 陡峭(历史包袱、未定义行为) | 陡峭(所有权/生命周期概念) |
| 典型场景 | 遗留系统、游戏、内核、HPC | 新系统服务、WebAssembly、CLI、基础设施 |
二、核心原理对比
2.1 内存管理模型
C++:RAII + 可选智能指针
- 资源获取即初始化(RAII):构造时获取资源,析构时释放。
- 可裸指针 + 手动
new/delete,也可用std::unique_ptr、std::shared_ptr等减少错误。 - 编译器不阻止悬垂指针、双重释放、use-after-free,需靠规范与静态分析。
Rust:所有权 + 借用
- 所有权:每个值有唯一所有者,离开作用域自动 drop,无 GC。
- 借用:通过引用(
&T/&mut T)临时借用,编译期检查引用合法性与可变性。 - 生命周期:标注引用与谁同寿,避免悬垂引用在编译期报错。
概念对照:
| C++ 概念 | Rust 近似概念 |
|---|---|
std::unique_ptr |
所有权(默认 move) |
std::shared_ptr |
Rc<T> / Arc<T> |
引用 T& |
借用 &T / &mut T |
| 析构函数 | Drop trait |
2.2 类型系统与泛型
C++
- 模板(Template):编译期多态,可特化、偏特化、SFINAE、C++20 Concept。
- 类型擦除:
std::function、虚函数、void*等。
Rust
- 泛型 + Trait:类似「接口」,可默认实现、泛型约束、trait object(动态分发)。
- 无继承,通过组合与 trait 实现多态。
2.3 错误处理
C++
- 异常(
throw/catch):灵活但可能影响性能与 ABI,部分项目禁用。 - 错误码、
std::optional、std::expected(C++23)等。
Rust
Result<T, E>:强制显式处理错误,?运算符传播错误。panic!用于不可恢复错误,类似「断言失败」。
三、语法与源码示例
3.1 你好世界
C++
1 |
|
Rust
1 | fn main() { |
3.2 变量与不可变/可变
C++
1 | const int x = 42; // 不可变 |
Rust
1 | let x = 42; // 默认不可变 |
3.3 结构体与实现
C++
1 | struct Point { |
Rust
1 | struct Point { |
3.4 枚举与模式匹配
C++(std::variant + std::visit,C++17)
1 |
|
Rust
1 | enum Message { |
3.5 错误处理
C++(错误码 + optional)
1 |
|
Rust
1 | fn parse_int(s: &str) -> Result<i32, std::num::ParseIntError> { |
3.6 所有权与移动
Rust(核心概念,C++ 无直接对应)
1 | fn main() { |
C++(拷贝/移动语义)
1 |
|
3.7 借用与引用
Rust
1 | fn len(s: &String) -> usize { |
C++
1 |
|
3.8 泛型与约束
C++(模板 + Concept,C++20)
1 |
|
Rust
1 | use std::ops::Add; |
3.9 并发:线程与同步
C++(std::thread + mutex)
1 |
|
Rust(Arc + Mutex)
1 | use std::sync::{Arc, Mutex}; |
四、内存与并发模型
4.1 C++ 内存模型简述
- 堆:
new/delete或智能指针管理。 - 栈:局部变量,自动管理。
- 未定义行为(UB):如 use-after-free、双重释放、数据竞争等,标准不保证行为,需避免。
4.2 Rust 内存模型与安全保证
- 栈上值默认,堆上用
Box<T>、Vec<T>等,由所有权与 drop 管理。 - 引用规则(借用检查):
- 任意时刻,要么多个不可变引用,要么一个可变引用。
- 引用不能比被引用者活得更久(生命周期检查)。
- 满足规则则无数据竞争、无悬垂引用,在编译期保证。
4.3 生命周期示例(Rust 独有)
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { |
五、实际项目应用案例
5.1 C++ 典型应用
- LLVM/Clang:编译器基础设施,大量模板与手写内存管理。
- Chromium:浏览器引擎,C++ 主导,复杂多进程与沙箱。
- Unreal Engine:游戏引擎,深度使用 C++ 与反射/蓝图。
- TensorFlow/PyTorch 底层:高性能算子与运行时多为 C++。
- MySQL/PostgreSQL:数据库核心用 C/C++ 实现。
5.2 Rust 典型应用
- Rust 编译器(rustc):自举,展示大型 Rust 项目与复杂类型系统。
- Firefox(Servo 组件):浏览器引擎实验,部分已合入 Firefox。
- Deno:TypeScript/JavaScript 运行时,核心用 Rust 重写。
- Discord:从 Go 迁移部分服务到 Rust,降低延迟与资源占用。
- Cloudflare:边缘逻辑、代理、零拷贝解析等用 Rust。
- AWS Firecracker:轻量级 VMM,用于 Lambda 等,安全与性能关键。
- 1Password:部分核心组件用 Rust 编写。
5.3 案例:从 C++ 到 Rust 的迁移(概念示例)
某团队将一高并发 TCP 代理从 C++ 迁移到 Rust 的动机与收益(概念性总结):
- 动机:偶发 use-after-free 与竞态,难以在测试中稳定复现。
- 做法:用 Rust 重写核心路径,保持协议与配置兼容;通过 FFI 或重写逐步替换。
- 收益:
- 编译通过即大幅排除内存与数据竞争类 bug。
- 无 GC 停顿,延迟与 C++ 版本相当或更稳定。
cargo与clippy提升协作与代码质量。
5.4 混合使用:Rust 调用 C++ / C++ 调用 Rust
Rust 调用 C 库(C++ 可 extern “C” 暴露)
1 | // 在 Rust 中声明 C 函数 |
C++ 调用 Rust(Rust 导出 C ABI)
1 | // lib.rs |
1 | // main.cpp |
实际项目常用 bindgen(C/C++ → Rust 绑定)与 cbindgen(Rust → C 头文件)做接口生成。
六、选型与迁移建议
6.1 何时优先 C++
- 已有大型 C++ 代码库,团队熟悉 C++。
- 强依赖现有 C++ 生态(如特定游戏引擎、HPC 库)。
- 需要与 C ABI 或 C++ ABI 深度耦合、对 ABI 稳定性有要求。
- 对语言标准与编译器行为有历史兼容需求。
6.2 何时优先 Rust
- 新项目,尤其重视内存安全与并发正确性。
- 系统软件、网络服务、命令行工具、WebAssembly 等。
- 希望减少内存与并发类 bug,愿意接受所有权与生命周期的学习成本。
- 希望统一构建、测试、格式化(cargo)与静态检查(clippy)。
6.3 迁移策略(C++ → Rust)
- 新模块用 Rust:在现有 C++ 系统中用 Rust 写新组件,通过 C ABI 或 gRPC/消息队列与 C++ 交互。
- 逐层替换:从边界服务或库开始,用 Rust 重写并保持接口一致。
- 双轨维护:关键路径先保留 C++,Rust 实现做并行验证与灰度。
- 工具:用
bindgen/cbindgen、cxx等减少手写 FFI,并补充测试与模糊测试。
小结
| 主题 | C++ 要点 | Rust 要点 |
|---|---|---|
| 内存 | RAII、智能指针、可手写任意指针 | 所有权、借用、生命周期、无 GC |
| 安全 | 依赖规范与工具 | 类型系统与借用检查强制保证 |
| 并发 | 需谨慎使用锁与原子 | 类型系统辅助避免数据竞争 |
| 抽象 | 模板、虚函数、Concept | 泛型、Trait、trait object |
| 错误处理 | 异常、错误码、optional | Result + ?,显式错误路径 |
| 生态与工具 | 标准委员会、多编译器、多构建系统 | Cargo、clippy、rustfmt 统一体验 |
两者都是系统级语言,C++ 更偏灵活与历史兼容,Rust 更偏安全与可维护。掌握两者有助于在不同场景下做出合适的技术选型,并在需要时进行混合编程或渐进式迁移。
文档中的代码示例均在 C++17/20 与 Rust 2021 下可编译运行,实际项目请以各自代码库与规范为准。