引用计数管理依赖构造、拷贝构造、赋值和析构函数协同,计数器须与共享资源共存于堆内存,通过指针共享;C++中以StringRep结构体封装数据与原子计数器,Python中需避免小整数缓存干扰。

构造块本身不直接参与引用计数管理,真正起作用的是构造函数、拷贝构造函数、赋值运算符和析构函数的协同设计。引用计数必须与共享资源绑定,不能作为普通成员变量独立存在,否则各对象副本会维护各自的计数器,失去“共享”意义。
引用计数必须与资源共存于堆内存
当多个对象需共享同一份资源(如字符串缓冲区、文件句柄、图像数据等),应将资源指针和引用计数器一同分配在堆上,并让所有对象持有指向该堆块的指针。
- 构造函数:分配资源 + 初始化计数器为1
- 拷贝构造函数:仅拷贝资源指针 + 原计数器原子递增
- 赋值运算符:右侧计数器递增,左侧原计数器递减;若减至0,则释放其资源和计数器
- 析构函数:计数器递减;若为0,同步释放资源和计数器
典型C++实现结构
以字符串类为例,核心逻辑如下:
- 内部持有一个 struct StringRep 指针:
StringRep* rep; -
StringRep 包含:
char* data、size_t len、size_t use_count - 构造时:
rep = new StringRep{new char[n+1], n, 1} - 拷贝构造时:
rep = rhs.rep; ++rep->use_count; - 析构时:
if (--rep->use_count == 0) { delete[] rep->data; delete rep; }
避免常见陷阱
引用计数失效往往源于设计疏漏:
- 计数器未用 指针或原子类型 管理 → 多个对象各自拷贝计数器值,无法同步
- 忘记在赋值运算符中处理左侧原资源的释放 → 内存泄漏
- 多线程环境下未加锁或未用
std::atomic_size_t→ 计数器竞态导致提前释放或泄漏 - 将小整数、短字符串等直接赋给成员变量(如
self.x = 100000)→ Python中这类小整数被缓存且全局复用,引用计数行为异常,不反映真实共享逻辑
Python中验证引用变化的实用技巧
使用 sys.getrefcount() 观察计数变动,但注意其参数本身会临时增加1次引用:
- 创建对象后立即查:计数通常为2(变量 + getrefcount调用)
- 赋值给新变量:+1;删除变量:−1
- 放入列表/字典:+1;从容器移除或容器销毁:−1
- 传入函数:调用期间+1;返回后自动−1
若想观察纯粹的资源引用关系,建议用 object() 或自定义类实例替代内置小整数——它们不会被缓存,引用行为更符合预期。










