【c++】智能指针以及实现
创始人
2025-05-30 18:02:59
0

1.auto_ptr(不要使用,auto_ptr是C++98的智能指针,C++11明确声明不再支持。)

最原始的智能指针。

auto_ptr具有以下缺陷:auto_ptr有拷贝语义,拷贝后源对象变得无效,这可能引发很严重的问题。由于 auto_ptr 基于【排他所有权模式】,这意味着:两个指针(同类型)不能指向同一个资源,复制或赋值都会改变资源的所有权。

复制auto_ptr对象时,把指针指传给复制出来的对象,原有对象的指针成员随后重置为nullptr。
使用auto_ptr要知道:
1. 智能指针不能共享指向对象的所有权
2. 智能指针不能指向数组。因为其实现中调用的是delete而非delete[]
3. 智能指针不能作为容器类的元素。


 2、unique_ptr(一种强引用指针)

它其实算是auto_ptr的翻版(都是独占资源的指针,内部实现也基本差不多).

但是unique_ptr的名字能更好的体现它的语义,而且在语法上比auto_ptr更安全(尝试复制unique_ptr时会编译期出错)

当你需要转移所有权,需要显式命令std::move,尽管转移所有权后 还是有可能出现原有指针调用(调用就崩溃)的情况。这个语法能强调你是在转移所有权,让你清晰的知道自己在做什么,从而不乱调用原有指针。 

void runGame(){std::unique_ptr b = new Base();std::unique_ptr b1 = b;//Error!编译期出错,不允许复制指针指向同一个资源。std::unique_ptr b2 = std::move(b);//转移所有权给b2.b->doSomething();//Oops!b指向nullptr,运行期崩溃
}

3、shared_ptr(一种强引用指针)
 

多个shared_ptr指向同一处资源,当所有shared_ptr都全部释放时,该处资源才释放。
每个shared_ptr都占指针的两倍空间,一个装着原始指针,一个装着计数区域(SharedPtrControlBlock)的指针

(用原始指针构造时,会new一个SharedPtrControlBlock出来作为计数存放的地方,然后用指针指向它,计数加减都通过SharedPtrControlBlock指针间接操作。)

//shared计数放在这个结构体里面,实际上结构体里还应该有另一个weak计数。下文介绍weak_ptr时会解释。
struct SharedPtrControlBlock{int shared_count;
};//大概长这个样子(化简版)
template
class shared_ptr{T* ptr;SharedPtrControlBlock* count;
};

 每次复制,多一个共享同处资源的shared_ptr时,计数+1。每次释放shared_ptr时,计数-1。
当shared计数为0时,则证明所有指向同一处资源的shared_ptr们全都释放了,则随即释放该资源(还会释放new出来的SharedPtrControlBlock)。

缺陷:模型循环依赖(互相引用或环引用)时,计数会不正常

//假如有这么一个怪物模型,它有2个亲人关系class Monster{std::shared_ptr m_father;std::shared_ptr m_son;
public:void setFather(std::shared_ptr& father);/void setSon(std::shared_ptr& son); ~Monster(){std::cout << "A monster die!";} 
};
//然后执行下面函数void runGame(){std::shared_ptr father = new Monster();std::shared_ptr son = new Monster();father->setSon(son);son->setFather(father);
}

猜猜执行完runGame()函数后,这对怪物父子能正确释放(发出死亡的悲鸣)吗?
答案是不能。
开始:
father,son指向的堆对象 shared计数都是为2,son智能指针退出栈:son指向的堆对象 计数减为1,father指向的堆对象 计数仍为2。father智能指针退出栈:father指向的堆对象 计数减为1 , son指向的堆对象 计数仍为1。

函数结束:所有计数都没有变0,也就是说中途没有释放任何堆对象。为了解决这一缺陷的存在,出现弱引用指针weak_ptr。

4、weak_ptr(一种弱引用指针)
 

weak_ptr只有某个对象的访问权,而没有它的生命控制权 即是 弱引用,所以weak_ptr是一种弱引用型指针,不控制所指向对象生存期的智能指针,它指向一个由shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr不会改变shared_ptr的引用计数。)

主要是为了解决两个问题:一是循环引用问题,使得资源无法释放;例如 A 对象含有一个 shared_ptr,而 B 对象也含有一个 shared_ptr,那么很容易产生循环引用,使得内存无法释放。

悬挂指针(dangling pointer):指针指向的内存被删除;一个简单的场景是,A 线程创建资源,并传递给 B 线程,B 线程只读访问资源;但是 A 线程随后可能释放了资源,B 没有感知,而得到了一个悬挂指针。)

内部实现:
计数区域(SharedPtrControlBlock)结构体引进新的int变量weak_count,来作为弱引用计数。
每个weak_ptr都占指针的两倍空间,一个装着原始指针,一个装着计数区域的指针(和shared_ptr一样的成员)。
weak_ptr可以由一个shared_ptr或者另一个weak_ptr构造。
weak_ptr的构造和析构不会引起shared_count的增加或减少,只会引起weak_count的增加或减少。

被管理资源的释放只取决于shared计数,当shared计数为0,才会释放被管理资源,也就是说weak_ptr不控制资源的生命周期。

但是计数区域的释放却取决于shared计数和weak计数,当两者均为0时,才会释放计数区域。

//shared引用计数和weak引用计数
//之前的计数区域实际最终应该长这个样子
struct SharedPtrControlBlock{int shared_count;int weak_count;
};//大概长这个样子(化简版)
template
class weak_ptr{T* ptr;SharedPtrControlBlock* count;
};

针对空悬指针问题:
空悬指针问题是指:无法知道指针指向的堆内存是否已经释放。

得益于引入的weak_count,weak_ptr指针可以使计数区域的生命周期受weak_ptr控制,

从而能使weak_ptr获取 被管理资源的shared计数,从而判断被管理对象是否已被释放。(可以实时动态地知道指向的对象是否被释放,从而有效解决空悬指针问题)

如果对象存在,lock()函数返回一个指向共享对象的shared_ptr(引用计数会增1),否则返回一个空shared_ptr。weak_ptr还提供了expired()函数来判断所指对象是否已经被销毁。

由于weak_ptr并没有重载operator ->和operator *操作符,因此不可直接通过weak_ptr使用对象,同时也没有提供get函数直接获取裸指针。典型的用法是调用其lock函数来获得shared_ptr示例,进而访问原始对象。
 

#include 
#include 
#include 
class T{public:T(int id): m_id(id){}int showid(){return m_id;}private:int m_id;
};void threadtest(std::weak_str t){std::this_thread::sleep_for(std::chrono::seconds(1));std::shared_ptr sp = t.lock();if(sp)std::cout<showID();                      
}
int main()
{std::shared_ptr sp = std::make_shared(1);std::thread t2(threadtest, sp);t2.join();return 0;
}


 

上一篇:23春-第三次集训题解

下一篇:smtp 抓包

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...