当前位置: 首页> 房产> 政策 > 无忧传媒在短视频领域的成就_深圳高端女装品牌排行榜_互联网运营推广是做什么的_东莞谷歌推广公司

无忧传媒在短视频领域的成就_深圳高端女装品牌排行榜_互联网运营推广是做什么的_东莞谷歌推广公司

时间:2025/7/11 22:24:39来源:https://blog.csdn.net/weixin_72357342/article/details/147195118 浏览次数:0次
无忧传媒在短视频领域的成就_深圳高端女装品牌排行榜_互联网运营推广是做什么的_东莞谷歌推广公司

🦄个人主页:修修修也

🎏所属专栏:C++

⚙️操作环境:Visual Studio 2022


目录

为什么需要智能指针

智能指针的使用及其实现原理

RAII

auto_ptr

简介

实现

unique_ptr

简介

实现

shared_ptr

简介

实现

weak_ptr

简介

实现

结语


为什么需要智能指针

        C++没有垃圾回收的机制,必须通过我们手动的去动态申请并释放资源。也就是说, 我们new出的资源, 必须在后面不使用之后将其delete掉, 否则就会造成内存泄漏。

        我在【C++】动态内存管理中详细介绍过内存泄漏的危害, 并提供了几种防止内存泄漏的方式, 其中最重要的一点就是要严格遵守谁申请谁释放原则, 这样就可以避免大量的内存泄漏场景, 一般而言,只要内存遵行了先申请后释放的原则, 那么100%是不可能内存泄漏的, 但是当C++引入异常这一特性的时候, 一切都变得不一样了...

        我们来看这段代码, 分析一下下面三种情况程序会出现什么问题:

int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}void Func()
{// 1、如果p1这里new 抛异常会如何?// 2、如果p2这里new 抛异常会如何?// 3、如果div调用这里又会抛异常会如何?int* p1 = new int;int* p2 = new int;cout << div() << endl;delete p1;delete p2;
}int main()
{try{Func();}catch (exception& e){cout << e.what() << endl;}return 0;
}

        不难发现,除了p1抛异常,剩下的两种情况都会导致不同程度的内存泄漏:

        那么是不是有异常的时候我们只能对着在执行流里乱窜的异常说:"太好了孩子们,是异常,我们没救了😅"。当然不是!!!乱世之中, 咱们的救世主悄然登场了:


智能指针的使用及其实现原理

        没错,智能指针就是救我们与水火之中的救世主, 那他的原理是什么呢?我们先来了解RAII思想:

RAII

        RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。

        它是在对象构造时获取资源, 接着控制对资源的访问使之在对象的生命周期内始终保持有效, 最后在对象析构时释放资源。因此, 我们实际上是把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

  • 不需要显式地释放资源
  • 采用这种方式, 对象所需要的资源在其生命周期内始终保持有效

auto_ptr

简介

        借助RAII思想, 我们的初代智能指针auto_ptr闪亮登场, 只是可惜这个初代目不太经打, 刚刚登场, 就已领了盒饭, 以至于后面被很多企业禁止使用, auto_ptr的主要败笔在于, 它在拷贝构造和赋值时使用了管理权转移的思想, 即把b赋值/拷贝构造给a时, 会直接把b的指针给a, 然后b自己置空。这样会导致b指针后续处于一个悬空状态, 后续如果继续不慎使用b则会造成空指针解引用的问题。而且在b生命周期结束后他会去析构一个空指针, 这完全就是一个非法的内存访问操作, 所以不可避免的会导致程序崩溃。如果b指针赋值后不置为空, 那么后续又会出现多重析构的问题。这导致了auto_ptr面世没多久就遭到了"封杀", 实在是可惜。但是智能指针并不因此挫折就销声匿迹了, 有此前车之鉴, 后续大佬们又在auto_ptr的基础上开发出了更加安全, 实用的智能指针。

实现

        以下是auto_ptr的简单模拟实现代码:

namespace test
{template<class T>class auto_ptr{public:auto_ptr(T* ptr = nullptr):_ptr(ptr){}//管理权转移,把ap.ptr的管理权转让给_ptr,然后ap.ptr自己置空auto_ptr(auto_ptr<T>& other): _ptr(other.ptr){other._ptr = nullptr;}~auto_ptr(){if (_ptr)delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}// 赋值运算符重载,转移所有权auto_ptr& operator=(auto_ptr& other) {if (this != &other) //检查是否自己给自己赋值{delete _ptr;	//先析构(放弃)自己原有的指针管理权_ptr = other.ptr;	//再拿到新的指针管理权other.ptr = nullptr;	//被转移对象自己置空}return *this;}private:T* _ptr;};
}

unique_ptr

简介

        auto_ptr的惨痛教训还历历在目, 于是C++痛定思痛, 推出了修补版本的unique_ptr。unique_ptr的想法是, 既然auto_ptr的赋值和拷贝构造会导致安全问题, 那么我把这两个操作禁用了不就ok了, 于是我们的二代智能指针就这样登场了。

实现

        unique_ptr在实现上和auto_ptr几乎一模一样, 但是对于拷贝构造函数和赋值运算符重载函数则是直接"封掉":

namespace test
{template<class T>class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr)delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//禁止拷贝构造unique_ptr(const unique_ptr& other) = delete;//禁止赋值unique_ptr& operator=(const unique_ptr& other) = delete;private:T* _ptr;};
}

shared_ptr

简介

        unique_ptr的改进为我们提供了相对安全的智能指针的方案, 但是由于他的实现思想的限制, 导致该智能指针在应用上有诸多限制, 例如不可以多个指针管理同一份资源, 也不可以赋值更改管理的资源。为了解决这一问题, 大佬们又出研发了一个史诗级的智能指针, 就是shared_ptr。

        shared_ptr借助了引用计数的思想, 支持多个智能指针管理同一份资源, 允许拷贝构造和赋值, 是通过为一份资源维护一份引用计数来实现的, 该引用计数记录了当前同时管理这份资源的智能指针数, 如果其中一个智能指针超出了生命周期要销毁资源,那么会先判断它是否是当前唯一管理这份资源,即引用计数是否为1, 如果是则析构释放资源, 如果不是那么只会将引用计数-1, 不会真实的去销毁资源。相应的,遇到拷贝构造和赋值则会相应的给引用计数+1。图示如下:

         shared_ptr可以说是智能指针的中流砥柱了, 但是即便如此, 它在某些场景中还是会出现一些无解的问题, 即在某些情况下会出现循环引用问题:

        首先我们可能会遇到使用智能指针管理链表资源的场景:

        然后我们需要将这两个链表结点连接起来:

        看起来好像没一点问题, 但是当我们要释放这两个结点的时候问题就出现了:

实现

        shared_ptr的实现比前面两个稍复杂一点, 引入引用计数后, 我们需要在构造,析构,拷贝构造和赋值函数中对引用计数做相应的处理, 但只要清楚了引用计数的原理,实现起来也非常简单:

namespace test
{template<class T>class shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pcount(new int(1)){}//如果引用计数为1才释放资源,否则只减引用计数~shared_ptr(){if (_ptr){if (*_pcount == 1){delete _ptr;delete _pcount;}else{(* _pcount)--;}}	}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//拷贝构造shared_ptr(const shared_ptr& other):_ptr(other._ptr),_pcount(other._pcount){(*_pcount)++;}//赋值shared_ptr& operator=(const shared_ptr& other){//判断自己给自己赋值if (_ptr == other._ptr){return *this;}//处理赋值对象管理的原资源if (*_pcount == 1){delete _ptr;delete _pcount;}else{(*_pcount)--;}//把新资源给赋值对象,同时增加引用计数_ptr = other._ptr;_pcount = other._pcount;++(*_pcount);return *this;}T* get(){return _ptr;}private:T* _ptr;int* _pcount;//用动态资源来管理引用计数,不能用普通类型,因为会导致每个类各自有一个//也不能用静态成员, 因为不能修改};
}

weak_ptr

简介

        weak_ptr是一种弱引用智能指针, 它是为配合 shared_ptr 而引入的,主要用于解决 shared_ptr 可能出现的循环引用问题。他不是RAII智能指针, 他不增加引用计数, 可以访问资源, 不参与资源释放的管理。

实现

        因为weak_ptr不参与资源的管理,所以实现的时候非常简单, 析构函数, 拷贝构造函数和赋值运算符重载都不需要实现, 系统默认生成的就可以使用, 但是除此之外, weak_ptr还要支持用shared_ptr来构造和赋值, 所以我们实现这两个函数:

namespace test
{template<class T>class weak_ptr{public:weak_ptr(T* ptr):_ptr(ptr){}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}//要支持用shared_ptr构造weak_ptr(const shared_ptr<T>& other):_ptr(other._ptr){}//支持用shared_ptr赋值weak_ptr& operator=(const shared_ptr<T>& other){_ptr = other.get();return *this;}private:T* _ptr;};
}

结语

希望这篇关于 C++智能指针 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

【C++11】左值引用、右值引用、移动语义和完美转发

【C++】STL标准模板库容器set

【C++】模拟实现二叉搜索(排序)树

【C++】模拟实现priority_queue(优先级队列)

【C++】模拟实现queue

【C++】模拟实现stack

【C++】模拟实现list

【C++】模拟实现vector

【C++】标准库类型vector

【C++】模拟实现string类

【C++】标准库类型string

【C++】构建第一个C++类:Date类

【C++】类的六大默认成员函数及其特性(万字详解)

【C++】什么是类与对象?



实际就是把动态开辟的资源交给智能指针来管理.

关键字:无忧传媒在短视频领域的成就_深圳高端女装品牌排行榜_互联网运营推广是做什么的_东莞谷歌推广公司

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: