news 2026/4/23 14:50:05

unique_ptr、shared_ptr、weak_ptr简易版实现记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
unique_ptr、shared_ptr、weak_ptr简易版实现记录

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

文章目录

      • 一、核心原理回顾
      • 二、代码实现
        • 1. 头文件依赖
        • 2. 实现unique_ptr(独占式)
        • 3. 实现shared_ptr(共享式)和weak_ptr(弱引用)
      • 三、测试代码
      • 四、扩展说明
      • 五、输出结果

要实现C++智能指针,核心是利用RAII(资源获取即初始化)机制:通过栈上的对象生命周期管理堆上的资源,析构时自动释放资源。下面分别实现独占式智能指针(unique_ptr)共享式智能指针(shared_ptr)弱引用智能指针(weak_ptr)(解决shared_ptr的循环引用问题)。

一、核心原理回顾

  1. unique_ptr:独占资源所有权,禁止拷贝,仅支持移动(所有权转移)。
  2. shared_ptr:共享资源所有权,通过引用计数管理,计数为0时释放资源。
  3. weak_ptr:不拥有资源,仅观察shared_ptr的资源,可避免循环引用,通过lock()方法获取可用的shared_ptr。

二、代码实现

1. 头文件依赖
#include<iostream>#include<utility>// std::swap#include<string>// 测试用#include<functional>// 可选:自定义删除器(本文简化版暂不实现)
2. 实现unique_ptr(独占式)
// 独占式智能指针template<typenameT>classUniquePtr{public:// 构造函数:接收原始指针(explicit避免隐式转换)explicitUniquePtr(T*p=nullptr):ptr_(p){}// 析构函数:释放资源~UniquePtr(){deleteptr_;ptr_=nullptr;}// 禁止拷贝构造(独占所有权,不能拷贝)UniquePtr(constUniquePtr&)=delete;// 禁止拷贝赋值UniquePtr&operator=(constUniquePtr&)=delete;// 移动构造:转移所有权UniquePtr(UniquePtr&&other)noexcept{ptr_=other.ptr_;other.ptr_=nullptr;// 原对象放弃所有权}// 移动赋值:转移所有权UniquePtr&operator=(UniquePtr&&other)noexcept{if(this!=&other){// 防止自赋值// 释放当前资源deleteptr_;// 接管原对象的资源ptr_=other.ptr_;other.ptr_=nullptr;}return*this;}// 重载解引用运算符T&operator*()const{return*ptr_;}// 重载箭头运算符T*operator->()const{returnptr_;}// 获取原始指针T*get()const{returnptr_;}// 释放所有权(返回原始指针,不释放资源)T*release(){T*p=ptr_;ptr_=nullptr;returnp;}// 重置指针(释放当前资源,接管新资源)voidreset(T*p=nullptr){if(ptr_!=p){// 防止重置为自身deleteptr_;ptr_=p;}}// 交换两个UniquePtr的资源voidswap(UniquePtr&other)noexcept{std::swap(ptr_,other.ptr_);}private:T*ptr_;// 指向资源的原始指针};
3. 实现shared_ptr(共享式)和weak_ptr(弱引用)

首先定义引用计数结构体(shared_ptr和weak_ptr共享),包含强引用计数(shared_ptr的数量)和弱引用计数(weak_ptr的数量)。

// 引用计数结构体(供shared_ptr和weak_ptr共享)structRefCount{intstrong_ref;// 强引用计数(shared_ptr)intweak_ref;// 弱引用计数(weak_ptr)RefCount():strong_ref(0),weak_ref(0){}RefCount(ints,intw):strong_ref(s),weak_ref(w){}};// 共享式智能指针template<typenameT>classSharedPtr{public:// 空构造函数SharedPtr():ptr_(nullptr),ref_count_(nullptr){}// 构造函数:接收原始指针explicitSharedPtr(T*p):ptr_(p){if(ptr_){// 强引用=1,弱引用=1(weak_ptr需要共享计数)ref_count_=newRefCount(1,1);}else{ref_count_=nullptr;}}// 析构函数:释放资源~SharedPtr(){release();}// 拷贝构造:共享资源,增加强引用计数SharedPtr(constSharedPtr&other){ptr_=other.ptr_;ref_count_=other.ref_count_;if(ref_count_){ref_count_->strong_ref++;}}// 移动构造:转移所有权,不修改计数SharedPtr(SharedPtr&&other)noexcept{ptr_=other.ptr_;ref_count_=other.ref_count_;// 原对象放弃所有权other.ptr_=nullptr;other.ref_count_=nullptr;}// 拷贝赋值:先释放当前资源,再共享新资源SharedPtr&operator=(constSharedPtr&other){if(this!=&other){// 防止自赋值release();// 释放当前资源// 接管新资源ptr_=other.ptr_;ref_count_=other.ref_count_;if(ref_count_){ref_count_->strong_ref++;}}return*this;}// 移动赋值:转移所有权SharedPtr&operator=(SharedPtr&&other)noexcept{if(this!=&other){// 防止自赋值release();// 释放当前资源// 接管原对象的资源ptr_=other.ptr_;ref_count_=other.ref_count_;// 原对象放弃所有权other.ptr_=nullptr;other.ref_count_=nullptr;}return*this;}// 重载解引用运算符T&operator*()const{return*ptr_;}// 重载箭头运算符T*operator->()const{returnptr_;}// 获取原始指针T*get()const{returnptr_;}// 获取强引用计数intuse_count()const{returnref_count_?ref_count_->strong_ref:0;}// 重置指针:释放当前资源,接管新资源voidreset(T*p=nullptr){release();// 释放当前资源// 接管新资源ptr_=p;if(ptr_){ref_count_=newRefCount(1,1);}else{ref_count_=nullptr;}}// 交换两个SharedPtr的资源voidswap(SharedPtr&other)noexcept{std::swap(ptr_,other.ptr_);std::swap(ref_count_,other.ref_count_);}private:T*ptr_;// 指向资源的原始指针RefCount*ref_count_;// 引用计数指针// 让weak_ptr访问私有成员template<typenameU>friendclassWeakPtr;// 释放资源的辅助函数voidrelease(){if(ref_count_){// 强引用计数减1ref_count_->strong_ref--;// 强引用计数为0时,释放资源if(ref_count_->strong_ref==0){deleteptr_;ptr_=nullptr;// 弱引用计数减1ref_count_->weak_ref--;// 弱引用计数为0时,释放引用计数对象if(ref_count_->weak_ref==0){deleteref_count_;ref_count_=nullptr;}}}}};// 弱引用智能指针(解决shared_ptr循环引用)template<typenameT>classWeakPtr{public:// 空构造函数WeakPtr():ptr_(nullptr),ref_count_(nullptr){}// 从SharedPtr构造:增加弱引用计数WeakPtr(constSharedPtr<T>&sp){ptr_=sp.ptr_;ref_count_=sp.ref_count_;if(ref_count_){ref_count_->weak_ref++;}}// 拷贝构造WeakPtr(constWeakPtr&other){ptr_=other.ptr_;ref_count_=other.ref_count_;if(ref_count_){ref_count_->weak_ref++;}}// 移动构造WeakPtr(WeakPtr&&other)noexcept{ptr_=other.ptr_;ref_count_=other.ref_count_;other.ptr_=nullptr;other.ref_count_=nullptr;}// 拷贝赋值WeakPtr&operator=(constWeakPtr&other){if(this!=&other){release();// 释放当前弱引用// 接管新弱引用ptr_=other.ptr_;ref_count_=other.ref_count_;if(ref_count_){ref_count_->weak_ref++;}}return*this;}// 移动赋值WeakPtr&operator=(WeakPtr&&other)noexcept{if(this!=&other){release();// 释放当前弱引用// 接管原对象的弱引用ptr_=other.ptr_;ref_count_=other.ref_count_;other.ptr_=nullptr;other.ref_count_=nullptr;}return*this;}// 从SharedPtr赋值WeakPtr&operator=(constSharedPtr<T>&sp){release();// 释放当前弱引用// 接管新弱引用ptr_=sp.ptr_;ref_count_=sp.ref_count_;if(ref_count_){ref_count_->weak_ref++;}return*this;}// 析构函数:释放弱引用~WeakPtr(){release();}// 锁定:返回可用的SharedPtr(若资源未释放)SharedPtr<T>lock()const{if(expired()){returnSharedPtr<T>();// 资源已释放,返回空shared_ptr}// 创建shared_ptr,增加强引用计数SharedPtr<T>sp;sp.ptr_=ptr_;sp.ref_count_=ref_count_;sp.ref_count_->strong_ref++;returnsp;}// 检查资源是否过期(强引用计数为0)boolexpired()const{return!ref_count_||ref_count_->strong_ref==0;}// 获取弱引用计数intweak_count()const{returnref_count_?ref_count_->weak_ref:0;}// 重置:释放当前弱引用voidreset(){release();ptr_=nullptr;ref_count_=nullptr;}// 交换两个WeakPtrvoidswap(WeakPtr&other)noexcept{std::swap(ptr_,other.ptr_);std::swap(ref_count_,other.ref_count_);}private:T*ptr_;// 指向资源的原始指针RefCount*ref_count_;// 引用计数指针// 释放弱引用的辅助函数voidrelease(){if(ref_count_){ref_count_->weak_ref--;// 弱引用计数为0时,释放引用计数对象if(ref_count_->weak_ref==0){deleteref_count_;ref_count_=nullptr;}}}};

三、测试代码

// 测试UniquePtrvoidtest_unique_ptr(){std::cout<<"===== 测试UniquePtr ====="<<std::endl;UniquePtr<int>up1(newint(10));std::cout<<*up1<<std::endl;// 输出:10// UniquePtr<int> up2 = up1; // 编译错误:禁止拷贝UniquePtr<int>up2=std::move(up1);// 移动构造if(up1.get()==nullptr){std::cout<<"up1移动后为空"<<std::endl;}std::cout<<*up2<<std::endl;// 输出:10up2.reset(newint(20));std::cout<<*up2<<std::endl;// 输出:20int*p=up2.release();// 释放所有权std::cout<<*p<<std::endl;// 输出:20deletep;// 手动释放(release不释放资源)}// 测试SharedPtrvoidtest_shared_ptr(){std::cout<<"\n===== 测试SharedPtr ====="<<std::endl;SharedPtr<std::string>sp1(newstd::string("Hello"));std::cout<<*sp1<<",强引用计数:"<<sp1.use_count()<<std::endl;// Hello,1SharedPtr<std::string>sp2=sp1;// 拷贝构造std::cout<<*sp2<<",强引用计数:"<<sp1.use_count()<<std::endl;// Hello,2sp1.reset(newstd::string("World"));std::cout<<*sp1<<",强引用计数:"<<sp1.use_count()<<std::endl;// World,1std::cout<<*sp2<<",强引用计数:"<<sp2.use_count()<<std::endl;// Hello,1SharedPtr<std::string>sp3=std::move(sp1);// 移动构造if(sp1.get()==nullptr){std::cout<<"sp1移动后为空"<<std::endl;}std::cout<<*sp3<<",强引用计数:"<<sp3.use_count()<<std::endl;// World,1}// 测试WeakPtrvoidtest_weak_ptr(){std::cout<<"\n===== 测试WeakPtr ====="<<std::endl;SharedPtr<int>sp(newint(100));WeakPtr<int>wp(sp);std::cout<<"弱引用计数:"<<wp.weak_count()<<std::endl;// 2(sp的弱引用=1,wp的弱引用+1=2)std::cout<<"资源是否过期:"<<std::boolalpha<<wp.expired()<<std::endl;// falseSharedPtr<int>sp2=wp.lock();// 锁定获取shared_ptrstd::cout<<*sp2<<",强引用计数:"<<sp2.use_count()<<std::endl;// 100,2sp.reset();// 释放sp的强引用(强引用计数=1)std::cout<<"资源是否过期:"<<std::boolalpha<<wp.expired()<<std::endl;// falsesp2.reset();// 释放sp2的强引用(强引用计数=0,资源释放)std::cout<<"资源是否过期:"<<std::boolalpha<<wp.expired()<<std::endl;// trueSharedPtr<int>sp3=wp.lock();// 资源已过期,返回空if(sp3.get()==nullptr){std::cout<<"sp3为空(资源已过期)"<<std::endl;}}intmain(){test_unique_ptr();test_shared_ptr();test_weak_ptr();return0;}

四、扩展说明

上述实现是简化版,标准库的智能指针还有以下特性可扩展:

  1. 支持数组unique_ptr<T[]>需要重载delete[]shared_ptr也可通过自定义删除器支持数组。
  2. 自定义删除器:允许用户指定资源的释放方式(如free、关闭文件句柄等)。
  3. 线程安全:标准库的shared_ptr引用计数操作是线程安全的(但对象访问不是),可通过原子操作(std::atomic)实现。
  4. 空指针优化:对空指针的引用计数进行优化,避免不必要的内存分配。

五、输出结果

===== 测试UniquePtr ===== 10 up1移动后为空 10 20 20 ===== 测试SharedPtr ===== Hello,强引用计数:1 Hello,强引用计数:2 World,强引用计数:1 Hello,强引用计数:1 sp1移动后为空 World,强引用计数:1 ===== 测试WeakPtr ===== 弱引用计数:2 资源是否过期:false 100,强引用计数:2 资源是否过期:false 资源是否过期:true sp3为空(资源已过期)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 14:45:52

多步推理与反思:解决复杂问题的新思路

多步推理与反思:解决复杂问题的新思路 关键词:多步推理、反思机制、复杂问题解决、人工智能、算法原理、数学模型、实际应用 摘要:本文聚焦于多步推理与反思这一解决复杂问题的新思路。首先介绍了该思路提出的背景,包括目的、适用读者、文档结构等。详细阐述了核心概念,通过…

作者头像 李华
网站建设 2026/4/23 13:04:28

<span class=“js_title_inner“>训练靠奖励,但奖励模型自己“瞎”了?奖励模型根本不懂“记忆”!</span>

在大语言模型迈向超长上下文处理的征程中&#xff0c;分段记忆架构已成为突破长上下文瓶颈的主流范式。记忆管理能力成为衡量模型性能的分水岭——既负责信息的跨片段传播&#xff0c;也确保模型在长程推理中不丢失关键信号。因此&#xff0c;利用奖励模型&#xff08;RMs&…

作者头像 李华
网站建设 2026/4/12 18:53:59

WebGL跨端兼容实战:移动端适配全攻略

复杂HTML项目重构实战&#xff08;多端适配增强版&#xff09;&#xff1a;PC移动端全兼容&#xff0c;WebGL/Cesium/音视频跨端落地 在之前的重构方案基础上&#xff0c;我们重点补充多端适配与兼容核心内容&#xff0c;覆盖PC&#xff08;桌面/平板&#xff09;与移动端&…

作者头像 李华
网站建设 2026/4/21 16:16:42

大数据领域数据架构的技术发展动态

大数据领域数据架构的技术发展动态&#xff1a;从“存储容器”到“智能中枢”的进化之路 1. 引入与连接&#xff1a;你每天都在“使用”数据架构 早上7点&#xff0c;你被手机闹钟叫醒&#xff0c;顺手刷了刷短视频APP——推荐页里全是你喜欢的“宠物搞笑”内容&#xff1b; …

作者头像 李华
网站建设 2026/4/16 17:44:28

国家气象中心 — 智能网格预报应用分析平台V3.0

01项目背景国家气象局于我们公司近几年一直保持合作关系&#xff0c;由于面对复杂气象数据处理需求&#xff0c;以及国家气象局对精细化预报、多模式对比分析的业务要求&#xff0c;构建一套专业、易用的智能网格预报应用分析平台迫在眉睫。我们分析用户的关键业务场景&#xf…

作者头像 李华