所有权模型

内容简介

所有权回答一个通用问题:谁负责释放、关闭或结束一个资源。资源可以是内存、文件句柄、网络连接、锁、线程、数据库连接,也可以是 UI 对象、协程任务或业务实体。

它不是 C++ 独有概念。C++ 只是把这个问题暴露得更直接:语言允许手动管理资源,所以所有权不清楚时,泄漏、重复释放、悬挂引用会很快出现。

为什么学 C++ 能帮助理解其他语言

很多语言都在用不同方式处理所有权:

语言/机制设计思路
C手动申请和释放,靠约定维护所有权
C++RAII、值语义、智能指针,把所有权放进类型和对象生命周期
Rust借用检查器在编译期检查所有权和借用
Java / Go / C#垃圾回收管理内存,但文件、锁、连接仍然需要明确释放
Python / JavaScript运行时管理对象生命周期,但外部资源仍需要上下文管理或显式关闭

所以所有权不是“指针问题”,而是资源生命周期问题。

常见关系

关系含义C++ 常见表达
独占所有权只有一个所有者负责释放资源std::unique_ptr<T>
共享所有权多个所有者共同延长资源生命周期std::shared_ptr<T>
弱观察观察共享资源但不延长生命周期std::weak_ptr<T>
只观察只使用,不负责释放T&T*
值拥有对象自己保存数据普通成员、std::stringstd::vector

基本原则

  • 先问清楚:谁拥有资源,谁只是在使用资源。
  • 能用值语义就用值语义。
  • 能让对象自动释放资源,就不要让调用者记得手动释放。
  • 共享所有权要谨慎,它通常比独占所有权更难推理。
  • 只观察对象时,不要伪装成拥有对象。

C++ 示例

#include <memory>
 
struct Widget {};
 
std::unique_ptr<Widget> create_widget()
{
    return std::make_unique<Widget>();
}
 
void use_widget(const Widget& widget)
{
    // 只使用,不拥有
}

返回 std::unique_ptr<Widget> 表示调用者拿到独占所有权;传 const Widget& 表示只观察,不负责释放。

易错点

Widget* create_widget()
{
    return new Widget();  // 调用者是否负责 delete?接口不清楚
}

这种接口容易泄漏,也容易重复释放。更清楚的写法是返回 std::unique_ptr<Widget>

迁移到其他语言的理解

  • 看到 with open(...)defer file.Close()try-with-resources,本质都是资源所有权和自动释放。
  • 看到 Rust 的 move、borrow、lifetime,本质是在编译期强制表达所有权。
  • 看到 Java/Go 的 GC,也要记住 GC 管内存,不代表所有资源都不用关闭。

相关:RAII智能指针移动语义cpp特殊成员函数