2026/4/17 21:34:53
网站建设
项目流程
国外最火的网站,画册设计内容,阿q的项目wordpress,ui设计个人作品集提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 一、核心原理回顾二、代码实现1. 头文件依赖2. 实现unique_ptr#xff08;独占式#xff09;3. 实现shared_ptr#xff08;共享式#xff09;和weak_ptr#x…提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档文章目录一、核心原理回顾二、代码实现1. 头文件依赖2. 实现unique_ptr独占式3. 实现shared_ptr共享式和weak_ptr弱引用三、测试代码四、扩展说明五、输出结果要实现C智能指针核心是利用RAII资源获取即初始化机制通过栈上的对象生命周期管理堆上的资源析构时自动释放资源。下面分别实现独占式智能指针unique_ptr、共享式智能指针shared_ptr和弱引用智能指针weak_ptr解决shared_ptr的循环引用问题。一、核心原理回顾unique_ptr独占资源所有权禁止拷贝仅支持移动所有权转移。shared_ptr共享资源所有权通过引用计数管理计数为0时释放资源。weak_ptr不拥有资源仅观察shared_ptr的资源可避免循环引用通过lock()方法获取可用的shared_ptr。二、代码实现1. 头文件依赖#includeiostream#includeutility// std::swap#includestring// 测试用#includefunctional// 可选自定义删除器本文简化版暂不实现2. 实现unique_ptr独占式// 独占式智能指针templatetypenameTclassUniquePtr{public:// 构造函数接收原始指针explicit避免隐式转换explicitUniquePtr(T*pnullptr):ptr_(p){}// 析构函数释放资源~UniquePtr(){deleteptr_;ptr_nullptr;}// 禁止拷贝构造独占所有权不能拷贝UniquePtr(constUniquePtr)delete;// 禁止拷贝赋值UniquePtroperator(constUniquePtr)delete;// 移动构造转移所有权UniquePtr(UniquePtrother)noexcept{ptr_other.ptr_;other.ptr_nullptr;// 原对象放弃所有权}// 移动赋值转移所有权UniquePtroperator(UniquePtrother)noexcept{if(this!other){// 防止自赋值// 释放当前资源deleteptr_;// 接管原对象的资源ptr_other.ptr_;other.ptr_nullptr;}return*this;}// 重载解引用运算符Toperator*()const{return*ptr_;}// 重载箭头运算符T*operator-()const{returnptr_;}// 获取原始指针T*get()const{returnptr_;}// 释放所有权返回原始指针不释放资源T*release(){T*pptr_;ptr_nullptr;returnp;}// 重置指针释放当前资源接管新资源voidreset(T*pnullptr){if(ptr_!p){// 防止重置为自身deleteptr_;ptr_p;}}// 交换两个UniquePtr的资源voidswap(UniquePtrother)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_ptrintweak_ref;// 弱引用计数weak_ptrRefCount():strong_ref(0),weak_ref(0){}RefCount(ints,intw):strong_ref(s),weak_ref(w){}};// 共享式智能指针templatetypenameTclassSharedPtr{public:// 空构造函数SharedPtr():ptr_(nullptr),ref_count_(nullptr){}// 构造函数接收原始指针explicitSharedPtr(T*p):ptr_(p){if(ptr_){// 强引用1弱引用1weak_ptr需要共享计数ref_count_newRefCount(1,1);}else{ref_count_nullptr;}}// 析构函数释放资源~SharedPtr(){release();}// 拷贝构造共享资源增加强引用计数SharedPtr(constSharedPtrother){ptr_other.ptr_;ref_count_other.ref_count_;if(ref_count_){ref_count_-strong_ref;}}// 移动构造转移所有权不修改计数SharedPtr(SharedPtrother)noexcept{ptr_other.ptr_;ref_count_other.ref_count_;// 原对象放弃所有权other.ptr_nullptr;other.ref_count_nullptr;}// 拷贝赋值先释放当前资源再共享新资源SharedPtroperator(constSharedPtrother){if(this!other){// 防止自赋值release();// 释放当前资源// 接管新资源ptr_other.ptr_;ref_count_other.ref_count_;if(ref_count_){ref_count_-strong_ref;}}return*this;}// 移动赋值转移所有权SharedPtroperator(SharedPtrother)noexcept{if(this!other){// 防止自赋值release();// 释放当前资源// 接管原对象的资源ptr_other.ptr_;ref_count_other.ref_count_;// 原对象放弃所有权other.ptr_nullptr;other.ref_count_nullptr;}return*this;}// 重载解引用运算符Toperator*()const{return*ptr_;}// 重载箭头运算符T*operator-()const{returnptr_;}// 获取原始指针T*get()const{returnptr_;}// 获取强引用计数intuse_count()const{returnref_count_?ref_count_-strong_ref:0;}// 重置指针释放当前资源接管新资源voidreset(T*pnullptr){release();// 释放当前资源// 接管新资源ptr_p;if(ptr_){ref_count_newRefCount(1,1);}else{ref_count_nullptr;}}// 交换两个SharedPtr的资源voidswap(SharedPtrother)noexcept{std::swap(ptr_,other.ptr_);std::swap(ref_count_,other.ref_count_);}private:T*ptr_;// 指向资源的原始指针RefCount*ref_count_;// 引用计数指针// 让weak_ptr访问私有成员templatetypenameUfriendclassWeakPtr;// 释放资源的辅助函数voidrelease(){if(ref_count_){// 强引用计数减1ref_count_-strong_ref--;// 强引用计数为0时释放资源if(ref_count_-strong_ref0){deleteptr_;ptr_nullptr;// 弱引用计数减1ref_count_-weak_ref--;// 弱引用计数为0时释放引用计数对象if(ref_count_-weak_ref0){deleteref_count_;ref_count_nullptr;}}}}};// 弱引用智能指针解决shared_ptr循环引用templatetypenameTclassWeakPtr{public:// 空构造函数WeakPtr():ptr_(nullptr),ref_count_(nullptr){}// 从SharedPtr构造增加弱引用计数WeakPtr(constSharedPtrTsp){ptr_sp.ptr_;ref_count_sp.ref_count_;if(ref_count_){ref_count_-weak_ref;}}// 拷贝构造WeakPtr(constWeakPtrother){ptr_other.ptr_;ref_count_other.ref_count_;if(ref_count_){ref_count_-weak_ref;}}// 移动构造WeakPtr(WeakPtrother)noexcept{ptr_other.ptr_;ref_count_other.ref_count_;other.ptr_nullptr;other.ref_count_nullptr;}// 拷贝赋值WeakPtroperator(constWeakPtrother){if(this!other){release();// 释放当前弱引用// 接管新弱引用ptr_other.ptr_;ref_count_other.ref_count_;if(ref_count_){ref_count_-weak_ref;}}return*this;}// 移动赋值WeakPtroperator(WeakPtrother)noexcept{if(this!other){release();// 释放当前弱引用// 接管原对象的弱引用ptr_other.ptr_;ref_count_other.ref_count_;other.ptr_nullptr;other.ref_count_nullptr;}return*this;}// 从SharedPtr赋值WeakPtroperator(constSharedPtrTsp){release();// 释放当前弱引用// 接管新弱引用ptr_sp.ptr_;ref_count_sp.ref_count_;if(ref_count_){ref_count_-weak_ref;}return*this;}// 析构函数释放弱引用~WeakPtr(){release();}// 锁定返回可用的SharedPtr若资源未释放SharedPtrTlock()const{if(expired()){returnSharedPtrT();// 资源已释放返回空shared_ptr}// 创建shared_ptr增加强引用计数SharedPtrTsp;sp.ptr_ptr_;sp.ref_count_ref_count_;sp.ref_count_-strong_ref;returnsp;}// 检查资源是否过期强引用计数为0boolexpired()const{return!ref_count_||ref_count_-strong_ref0;}// 获取弱引用计数intweak_count()const{returnref_count_?ref_count_-weak_ref:0;}// 重置释放当前弱引用voidreset(){release();ptr_nullptr;ref_count_nullptr;}// 交换两个WeakPtrvoidswap(WeakPtrother)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_ref0){deleteref_count_;ref_count_nullptr;}}}};三、测试代码// 测试UniquePtrvoidtest_unique_ptr(){std::cout 测试UniquePtr std::endl;UniquePtrintup1(newint(10));std::cout*up1std::endl;// 输出10// UniquePtrint up2 up1; // 编译错误禁止拷贝UniquePtrintup2std::move(up1);// 移动构造if(up1.get()nullptr){std::coutup1移动后为空std::endl;}std::cout*up2std::endl;// 输出10up2.reset(newint(20));std::cout*up2std::endl;// 输出20int*pup2.release();// 释放所有权std::cout*pstd::endl;// 输出20deletep;// 手动释放release不释放资源}// 测试SharedPtrvoidtest_shared_ptr(){std::cout\n 测试SharedPtr std::endl;SharedPtrstd::stringsp1(newstd::string(Hello));std::cout*sp1强引用计数sp1.use_count()std::endl;// Hello1SharedPtrstd::stringsp2sp1;// 拷贝构造std::cout*sp2强引用计数sp1.use_count()std::endl;// Hello2sp1.reset(newstd::string(World));std::cout*sp1强引用计数sp1.use_count()std::endl;// World1std::cout*sp2强引用计数sp2.use_count()std::endl;// Hello1SharedPtrstd::stringsp3std::move(sp1);// 移动构造if(sp1.get()nullptr){std::coutsp1移动后为空std::endl;}std::cout*sp3强引用计数sp3.use_count()std::endl;// World1}// 测试WeakPtrvoidtest_weak_ptr(){std::cout\n 测试WeakPtr std::endl;SharedPtrintsp(newint(100));WeakPtrintwp(sp);std::cout弱引用计数wp.weak_count()std::endl;// 2sp的弱引用1wp的弱引用12std::cout资源是否过期std::boolalphawp.expired()std::endl;// falseSharedPtrintsp2wp.lock();// 锁定获取shared_ptrstd::cout*sp2强引用计数sp2.use_count()std::endl;// 1002sp.reset();// 释放sp的强引用强引用计数1std::cout资源是否过期std::boolalphawp.expired()std::endl;// falsesp2.reset();// 释放sp2的强引用强引用计数0资源释放std::cout资源是否过期std::boolalphawp.expired()std::endl;// trueSharedPtrintsp3wp.lock();// 资源已过期返回空if(sp3.get()nullptr){std::coutsp3为空资源已过期std::endl;}}intmain(){test_unique_ptr();test_shared_ptr();test_weak_ptr();return0;}四、扩展说明上述实现是简化版标准库的智能指针还有以下特性可扩展支持数组unique_ptrT[]需要重载delete[]shared_ptr也可通过自定义删除器支持数组。自定义删除器允许用户指定资源的释放方式如free、关闭文件句柄等。线程安全标准库的shared_ptr的引用计数操作是线程安全的但对象访问不是可通过原子操作std::atomic实现。空指针优化对空指针的引用计数进行优化避免不必要的内存分配。五、输出结果 测试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为空资源已过期