C++ 专家(23):C++ vs Rust——所有权、生命周期、编译期检查、安全性
更新时间:2026-09-01。本文是
languages/cpp/expert/专家层第 23 篇,接 Pimpl 惯用法。Rust 是近年来系统编程领域最受关注的语言。C++ 和 Rust 都追求"零开销抽象",但 Rust 通过所有权系统和借用检查在编译期保证内存安全。理解 Rust 能帮 C++ 开发者反思自己的编码习惯。
本文要回答的问题
- Rust 的所有权系统和 C++ 的 RAII 有什么本质区别?
- 生命周期(lifetime)是什么?C++ 有生命周期吗?
- Rust 如何保证内存安全?C++ 如何避免内存安全问题?
- C++ 和 Rust 的互操作性怎么样?什么时候用 C++ 什么时候用 Rust?
一、所有权 vs RAII
cpp
// C++ RAII:资源获取即初始化,析构函数释放资源
class Buffer {
int* data;
public:
Buffer(size_t n) : data(new int[n]) {}
~Buffer() { delete[] data; }
// 需要实现拷贝/移动语义
};
// 问题:忘记实现拷贝/移动、析构函数不虚、裸指针可能泄漏rust
// Rust 所有权:每个值只有一个所有者
// 离开作用域自动释放,不需要写析构函数
fn process() {
let v = vec![1, 2, 3]; // v 拥有 vector
// 使用 v
// 离开作用域,v 自动释放
}
// 移动语义:所有权转移
fn take(v: Vec<i32>) { // v 获得所有权
// 使用 v
} // v 在这里释放
fn main() {
let v = vec![1, 2, 3];
take(v);
// println!("{:?}", v); // ❌ 编译错误:v 的所有权已转移
}本质区别: C++ 的 RAII 是约定,Rust 的所有权是编译器强制检查的。
二、生命周期
rust
// Rust 生命周期:编译器检查引用是否有效
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// 'a 表示:x 和 y 的生命周期必须至少和 'a 一样长
// 返回的引用生命期也受 'a 约束
// 编译器检查:不会出现悬垂引用
fn dangling() -> &String {
let s = String::from("hello");
&s // ❌ 编译错误:s 离开作用域后引用无效
}cpp
// C++ 中同样的检查只能靠开发者经验
// 返回局部变量的引用是 UB,但编译器只能警告
const std::string& dangling() {
std::string s = "hello";
return s; // 警告:返回局部引用,但可以编译通过
}三、借用检查
rust
// 借用规则:要么有多个不可变引用,要么有一个可变引用
fn main() {
let mut v = vec![1, 2, 3];
let r1 = &v; // 不可变借用
let r2 = &v; // 不可变借用,可以多个
// let r3 = &mut v; // ❌ 编译错误:已有不可变借用时不能可变借用
// 使用完 r1, r2 后
let r3 = &mut v; // OK
r3.push(4);
}cpp
// C++ 中同样的问题需要开发者自己注意
std::vector<int> v = {1, 2, 3};
int& r1 = v[0];
const int& r2 = v[1];
// v.push_back(4); // 可能导致 reallocation,r1 和 r2 悬垂
// 编译器不会报错,运行时 UB四、C++ 和 Rust 的互操作性
rust
// 从 Rust 调用 C++ 函数
extern "C" {
fn cpp_function(x: i32) -> i32;
}
// 从 C++ 调用 Rust 函数
#[no_mangle]
pub extern "C" fn rust_function(x: i32) -> i32 {
x * 2
}cpp
// C++ 侧
extern "C" int rust_function(int x);
// C++ 调用 Rust
int result = rust_function(5);五、什么时候用 C++,什么时候用 Rust?
| 场景 | 推荐语言 | 原因 |
|---|---|---|
| 大型遗留系统 | C++ | 已有代码库和人力 |
| 新系统级项目 | Rust | 内存安全,现代工具链 |
| 游戏引擎 | C++ | 成熟生态,Unreal 等 |
| 嵌入式 | Rust/C++ | Rust 安全,C++ 生态 |
| 高性能计算 | C++ | CUDA、OpenMP 生态 |
| Web 组件 | Rust | WASM 支持好 |
| 工具链 | Rust | cargo 比 CMake 好用 |
六、常见坑对照
| 坑 | C++ 现象 | Rust 现象 |
|---|---|---|
| 悬垂指针 | UB,运行时崩溃 | 编译错误 |
| 数据竞争 | UB,难以调试 | 编译错误 |
| 迭代器失效 | UB,运行时崩溃 | 借用检查阻止 |
| 内存泄漏 | 可能泄漏 | 不会泄漏 |
| 异常安全 | 需要手动处理 | 无异常,Result 处理 |
相关与延伸
下一篇:C++ 性能优化实战——性能分析、优化技巧、常见模式;C++ RAII 入门,见 RAII 与智能指针。
一句话总结
C++ vs Rust:Rust 的所有权系统是编译器强制检查的,C++ 的 RAII 是约定,执行依赖开发者;生命周期在 Rust 中由编译器检查,C++ 中靠开发者经验;借用检查在 Rust 中保证要么多个不可变引用要么一个可变引用;C++ 和 Rust 通过 extern "C" 互操作;新系统级项目推荐 Rust,大型遗留系统用 C++,游戏引擎用 C++,嵌入式两者都可。