您的位置:首页 > 新闻 > 会展 > 百度关键词_网页制作主题成品_永久免费的建站系统有哪些_广州网络推广

百度关键词_网页制作主题成品_永久免费的建站系统有哪些_广州网络推广

2024/12/22 16:00:53 来源:https://blog.csdn.net/2301_80655639/article/details/144632784  浏览:    关键词:百度关键词_网页制作主题成品_永久免费的建站系统有哪些_广州网络推广
百度关键词_网页制作主题成品_永久免费的建站系统有哪些_广州网络推广

目录

RAII

C++标准库智能指针

auto_ptr

unique_ptr

 shared_ptr

循环引用问题

shared_ptr的线程安全问题 

weak_ptr


RAII

RAII是Resource Acquisition Is Initialization的缩写,他是一种资源管理的类的设计思想

本质是利用对象生命周期来管理获取到的动态资源,避免资源泄漏

RAII在获取资源时把资源委托给一个对象,控制着对资源的访问,资源在对象的生命周期内始终保持有效,最后在对象析构时释放资源,保证了资源的正常释放,避免资源泄露的问题

智能指针类就满足RAII的设计思路

C++标准库智能指针

C++标准库中的智能指针都在<memory>这个头文件下面

智能指针有好几种,除了weak_ptr他们都符合RAII和像指针一样的访问行为,原理上是解决智能指针拷贝时思路的不同

auto_ptr是C++98设计出来的智能指针,他的特点是拷贝时把被拷贝对象的资源管理权转给拷贝对象,这会导致他会让被拷贝对象悬空,导致访问报错的问题,强烈不建议使用auto_ptr

unique_ptr是C++11设计出来的智能指针,翻译是唯一指针,他的特点是不支持拷贝,只支持移动,不需要拷贝的场景就非常建议使用他

shared_ptr是C++11设计出来的智能指针,翻译是共享指针,他的特点是支持拷贝,也支持移动,如果需要拷贝的场景就需要使用他。底层实现方式是引用计数

weak_ptr是C++11设计出来的智能指针,翻译是弱指针,他不同于上面的智能指针,他不支持RAII,也就意味着不能用他来直接管理资源,weak_ptr的产生本质是要解决share_ptr的一个循环引用导致内存泄漏的问题

auto_ptr

template<class T>
class auto_ptr
{
public:auto_ptr(T* ptr):_ptr(ptr){}auto_ptr(auto_ptr<T>& sp):_ptr(sp._ptr){// 管理权转移sp._ptr = nullptr;}auto_ptr<T>& operator=(auto_ptr<T>& ap){// 检测是否为自己给自己赋值if (this != &ap){// 释放当前对象中资源if (_ptr)delete _ptr;// 转移ap中资源到当前对象中_ptr = ap._ptr;ap._ptr = NULL;}return *this;}~auto_ptr(){if (_ptr){cout << "delete:" << _ptr << endl;delete _ptr;}}// 像指针一样使用T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};

unique_ptr

template<class T>
class unique_ptr
{
public:explicit unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr){cout << "delete:" << _ptr << endl;delete _ptr;}}// 像指针⼀样使⽤T& operator*(){return *_ptr;}T* operator->(){return _ptr;}unique_ptr(const unique_ptr<T>& sp) = delete;unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;unique_ptr(unique_ptr<T>&& sp):_ptr(sp._ptr){sp._ptr = nullptr;}unique_ptr<T>& operator=(unique_ptr<T>&& sp){delete _ptr;_ptr = sp._ptr;sp._ptr = nullptr;}
private:T* _ptr;
};

 shared_ptr

template<class T>
class shared_ptr
{
public:explicit shared_ptr(T* ptr = nullptr):_ptr(ptr),_pcount(new int(1)){}template<class D>shared_ptr(T* ptr, D del):_ptr(ptr),_pcount(new int(1)),_del(del){}shared_ptr(shared_ptr<T>& sp):_ptr(sp._ptr),_pcount(sp._pcount),_del(sp._del){(*_pcount)++;}void release(){if (--(*_pcount) == 0){_del(_ptr);delete _pcount;_ptr = _pcount = nullptr;}}shared_ptr<T>& operator=(const shared_ptr<T>& sp){if (_ptr != sp._ptr){release();_ptr = sp._ptr;_pcount = sp._pcount;_del = sp._del;(*_pcount)++;}}~shared_ptr(){release();}T* get() const{return _ptr;}int use_count() const{return *_pcount;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;int* _pcount;function<void(T*)> _del = [](T* ptr) {delete ptr; }; // 删除器
};

shared_ptr管理一份资源就需要一份引用计数,所有引用计数用静态成员的方式是无法解决的,而是采用了堆上动态开辟的方式

当构造智能指针对象时来一份资源就要new一个引用计数,多个shared_ptr指向资源时就++引用计数即可,当shared_ptr析构时只需要--引用计数,当引用计数--到0后代表当前析构的shared_ptr是最后一个管理资源的对象,则析构资源

循环引用问题

若有如下代码

struct ListNode
{int data;std::shared_ptr<ListNode> _next;std::shared_ptr<ListNode> _prev;
};int main()
{std::shared_ptr<ListNode> n1(new ListNode);std::shared_ptr<ListNode> n2(new ListNode);n1->next = n2;n2->prev = n1;return 0;
}

 

n1和n2析构后,管理两个节点的引用计数减到1

右边的节点释放需要左边的next不再管理,next析构后右边的节点就可以释放

next是左边的节点,而左边的节点释放需要右边的prev不再管理,prev释放后next才可以释放

prev是右边的节点,右边的节点需要右边的节点释放,至此逻辑上就形成了循环引用,谁都不会释放,导致内存泄漏

解决这个问题只需要把ListNode结构体中的next和prev改成weak_ptr,weak_ptr绑定到shared_ptr时不会增加它的引用计数,next和prev不再参与资源释放管理逻辑,就成功的打破了引用循环

struct ListNode
{int data;std::weak_ptr<ListNode> _next;std::weak_ptr<ListNode> _prev;
};

shared_ptr的线程安全问题 

shared_ptr的引用计数在堆上,如果多个shared_ptr对象在多个线程中进行拷贝析构的操作修改引用计数,就会存在线程安全问题,所以shared_ptr引用计数是需要加锁或者原子操作保证线程安全的

我们可以在shared_ptr引用计数从int*改成atomic<int*>就可以保证引用计数的线程安全问题,或者使用互斥锁加锁也可以

private:T* _ptr;atomic<int*> _pcount;function<void(T*)> _del = [](T* ptr) {delete ptr; }; // 删除器
};

weak_ptr

template<class T>
class weak_ptr
{
public:weak_ptr(){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}
private:T * _ptr = nullptr;
};

weak_ptr不支持RAII,不支持访问资源,只支持绑定到shared_ptr,且不增加shared_ptr的引用计数,用来解决shared_ptr循环引用的问题

weak_ptr没有重载operator*和operator->等,因为它不参与资源管理,如果它绑定的shared_ptr已经释放了资源,weak_ptr再去访问资源是很危险的


完 

版权声明:

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

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