news 2026/4/18 10:34:12

int * 代替外部计数结构体实现SharedPtr

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
int * 代替外部计数结构体实现SharedPtr

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

    • 一、核心矛盾点
    • 二、错误实现演示与问题分析
      • 错误代码片段
      • 测试场景与崩溃后果
      • 核心问题总结
    • 三、正确方案的本质:用指针共享堆上的计数
      • 简化优化:不用结构体,只用 `int*`
    • 四、补充解答:结构体是必须的吗?
    • 五、总结

我有一个疑问RefCount必须以一个类或者结构体放置在外面吗,这里面本质不就是一个计数吗,能不能把这个计算int类型变量直接放置在sharedptr类中作为成员变量呢,请说明行或者不行及其原因

结论先行:绝对不行,不能将引用计数直接作为SharedPtr的普通int成员变量,这违背了shared_ptr共享计数的核心设计原理。下面结合底层逻辑、错误案例、后果分析,为你详细解释原因,同时给出简化的正确实现方案。


一、核心矛盾点

shared_ptr的设计目标:多个智能指针对象共享同一个资源,且共用同一个引用计数,计数的增减对所有共享该资源的指针都生效。

  • 类的普通成员变量(值类型):属于对象独占,每个SharedPtr实例都会独立拥有一份成员变量副本,彼此隔离、无法同步;
  • 引用计数的需求:必须是全局唯一、所有共享实例都能访问修改的共享变量。

这是直接用int成员变量无法解决的本质矛盾。


二、错误实现演示与问题分析

我们模拟你设想的写法,把计数直接作为成员变量,看看会发生什么致命问题:

错误代码片段

template<typenameT>classBadSharedPtr{private:T*ptr_;intref_count_;// 直接将计数作为普通成员变量(错误写法)public:// 构造函数explicitBadSharedPtr(T*p=nullptr):ptr_(p),ref_count_(0){if(ptr_)ref_count_=1;}// 拷贝构造:拷贝指针和计数值BadSharedPtr(constBadSharedPtr&other){ptr_=other.ptr_;ref_count_=other.ref_count_;ref_count_++;// 尝试给当前对象的计数+1}// 析构函数~BadSharedPtr(){ref_count_--;if(ref_count_==0){deleteptr_;std::cout<<"资源释放\n";}}T&operator*(){return*ptr_;}intuse_count()const{returnref_count_;}};

测试场景与崩溃后果

voidtest(){BadSharedPtr<int>sp1(newint(10));// sp1.ptr_ → 堆内存,sp1.ref_count_ = 1BadSharedPtr<int>sp2=sp1;// 拷贝构造:sp2.ptr_ 和 sp1 指向同一块内存// sp2.ref_count_ = 2,sp1.ref_count_ 仍然是 1(两个独立变量!)std::cout<<sp1.use_count();// 输出 1std::cout<<sp2.use_count();// 输出 2}// 函数退出,析构顺序:sp2 先析构 → sp2.ref_count=1,不释放资源// sp1 后析构 → sp1.ref_count=0,释放资源 ✔️ 看似没问题?// 进阶场景:多一层拷贝BadSharedPtr<int>sp3=sp2;// 析构时:sp3计数减到1、sp2计数减到1、sp1计数减到0 → 仅释放一次// 但如果执行 reset、赋值操作,会直接崩溃:sp1.reset();// sp1 计数减为0,释放内存;但 sp2/sp3 仍持有该内存指针,变成野指针!// sp2 析构时会再次 delete 同一块内存 → **重复释放,程序崩溃**

核心问题总结

  1. 计数隔离,无法同步:每个对象的ref_count_都是独立副本,修改一个不会影响其他对象,计数彻底失效;
  2. 重复释放/内存泄漏:无法准确判断资源的真实引用数量,要么重复释放内存导致崩溃,要么计数永远不为0导致内存泄漏;
  3. 行为不可控:赋值、reset、移动等操作都会产生未定义行为。

三、正确方案的本质:用指针共享堆上的计数

要实现唯一且共享的计数,必须将计数对象分配在堆内存上,所有SharedPtr实例只存储一个指针,指向这块堆内存。
所有实例通过指针访问同一个计数变量,修改后全局同步,这也是我们最初用RefCount结构体/int*的核心原因。

简化优化:不用结构体,只用int*

你之前看到的RefCount结构体是为了扩展(兼容弱引用计数),如果仅实现基础共享计数,完全可以去掉结构体,直接用int*作为成员变量,这是最精简的正确写法:

#include<iostream>#include<utility>#include<string>template<typenameT>classSharedPtr{private:T*ptr_;// 托管资源指针int*ref_cnt_;// 指针:指向堆上的唯一引用计数(核心修正)// 私有释放逻辑voidrelease(){if(ref_cnt_){--(*ref_cnt_);// 计数为0,释放资源和计数对象if(*ref_cnt_==0){deleteptr_;deleteref_cnt_;}// 清空当前对象指针ptr_=nullptr;ref_cnt_=nullptr;}}public:// 空构造SharedPtr():ptr_(nullptr),ref_cnt_(nullptr){}// 有参构造explicitSharedPtr(T*p):ptr_(p){if(ptr_){ref_cnt_=newint(1);// 堆上分配计数,初始值1}else{ref_cnt_=nullptr;}}// 拷贝构造:共享指针和计数,计数+1SharedPtr(constSharedPtr&other){ptr_=other.ptr_;ref_cnt_=other.ref_cnt_;// 共享同一个计数指针if(ref_cnt_){++(*ref_cnt_);}}// 移动构造:转移所有权,不修改计数SharedPtr(SharedPtr&&other)noexcept{ptr_=other.ptr_;ref_cnt_=other.ref_cnt_;other.ptr_=nullptr;other.ref_cnt_=nullptr;}// 拷贝赋值SharedPtr&operator=(constSharedPtr&other){if(this!=&other){release();ptr_=other.ptr_;ref_cnt_=other.ref_cnt_;if(ref_cnt_)++(*ref_cnt_);}return*this;}// 析构函数~SharedPtr(){release();}// 工具函数T&operator*()const{return*ptr_;}T*operator->()const{returnptr_;}intuse_count()const{returnref_cnt_?*ref_cnt_:0;}voidreset(T*p=nullptr){release();ptr_=p;if(ptr_)ref_cnt_=newint(1);}};

四、补充解答:结构体是必须的吗?

不是必须的!

  • 基础场景:用int*就足够实现共享计数;
  • 扩展场景:需要弱引用计数、自定义删除器、原子操作标记等附加信息时,用结构体封装多个变量更优雅(这也是标准库和我们最初代码用RefCount的原因);
  • 核心约束不变:计数必须存储在堆上,通过指针共享,不能是类的值类型成员

五、总结

  1. 不行的根本原因:普通int成员变量是对象独占的,无法让多个SharedPtr共享同一个计数,会导致计数失效、内存崩溃;
  2. 正确实现规则:引用计数必须分配在堆内存中,所有智能指针对象通过指针共享这块内存,保证计数全局同步;
  3. 简化写法:无需结构体,用int*即可实现基础功能,结构体仅用于代码扩展和规范化管理。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 10:04:34

基于STM32的二维码识别系统的设计与实现

基于STM32的二维码识别系统的设计与实现 第一章 绪论 传统二维码识别多依赖专用扫码设备或移动端APP&#xff0c;存在硬件成本高、集成性差、适配嵌入式场景能力弱等问题&#xff0c;难以满足工业产线、物流分拣、门禁管理等场景下轻量化、定制化的扫码需求。STM32单片机凭借高…

作者头像 李华
网站建设 2026/4/3 6:26:47

基于STM32单片机自动迎客门设计

基于STM32单片机的自动迎客门设计 第一章 绪论 传统商用/家用入户门多采用手动开合方式&#xff0c;存在操作便捷性差、缺乏智能交互、无法适配迎宾场景等问题&#xff0c;尤其在商铺、展厅、高端住宅等场景&#xff0c;难以满足人性化迎客、便捷通行的需求。STM32单片机凭借…

作者头像 李华
网站建设 2026/4/8 20:38:21

导师严选!万众偏爱的AI论文平台 —— 千笔AI

你是否曾为论文选题发愁&#xff0c;反复修改却仍不满意&#xff1f;文献查找耗时费力&#xff0c;格式排版总是出错&#xff0c;查重率又让人焦虑不已&#xff1f;面对这些学术写作的“老大难”&#xff0c;许多同学都感到力不从心。而千笔AI&#xff0c;正是为解决这些问题而…

作者头像 李华