C++ 智能指针——简单实现以及循环引用问题
来源:互联网 发布:手机mac过滤怎么设置 编辑:程序博客网 时间:2024/06/11 10:22
智能指针 smart pointer
一.智能指针及其发展史
什么是智能指针呢?
现阶段的智能指针(smart pointer)的一种通用实现技术,是使用引用计数(reference count)。智能指针类将一个
计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。
智能指针的原理就是管理资源的RALL机制(RALL机制便是通过利用对象的自动销毁,使得资源也具有了生命周
期,有了自动销毁,自动回收的功能)。RAII全称为Resource Acquisition Is Initialization,它是在一些面向对象语
言中的一种惯用法。资源分配即初始化,定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始
化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。RAII要求,资源的有效期与持有资源的对象的
生命期严格绑定,即由对象的构造函数完成资源的分配,同时由析构函数完成资源的释放。在这种要求下,只要
对象能正确地析构,就不会出现资源泄露问题。
从另一个角度看,智能指针是存储指向动态分配(堆)对象指针的类。除了能够在适当的时间自动删除指向的对
象外,他们的工作机制很像C++的内置指针。智能指针在面对异常的时候格外有用,因为他们能够确保正确的销毁动
态分配的对象。他们也可以用于跟踪被多用户共享的动态分配对象。
事实上,智能指针能够做的还有很多事情,例如处理线程安全,提供写时复制,确保协议,并且提供远程交互服
务。有能够为这些ESP (Extremely Smart Pointers)创建一般智能指针的方法,但是并没有涵盖进来。智能指针的大部
分使用是用于生存期控制,阶段控制。它们使用operator->和operator*来生成原始指针,这样智能指针看上去就像一
个普通指针。
智能指针的发展史:
第一阶段(C++98):
auto_ptr —— 自动指针
auto_ptr 的主要思想是 管理权转移
但其缺陷很大,当通过拷贝构造函数,通过操作符=赋值后,原来的那个智能指针对象就失效了。只有新的智能
指针对象可以有效使用了。被包装的指针指向的内存块就像是一份独享占用的财产,当通过复制构造,通过=赋
值传给别的智能指针对象时,原有的对象就失去了对那块内存区域的拥有权。
简单的说,也就是任何时候只能有一个智能指针对象指向那块内存区域,不能有两个对象同时指向那块内存区域。
第二阶段(C++03):
即在Boost中的智能指针:
scoped_ptr —— 守卫指针
scoped_ptr的主要思想是 防拷贝
share_ptr —— 共享指针
weak_ptr —— 用于解决share_ptr的循环引用缺陷问题
share_ptr的主要思想是 引用计数
boost库中提供了一种新型的智能指针shared_ptr,它解决了在多个指针间共享对象所有权的问题,同时也满足容
器对元素的要求,因而可以安全地放入容器中。
第三阶段(C++11):
unique_ptr
share_ptr
weak_ptr
unique_ptr还是运用了 防拷贝 的思想
unique_ptr是一种定义在<memory>中的智能指针。它持有对对象的独有权——两个unique_ptr不能指向一个对
象,不能进行复制操作只能进行移动操作。
二.智能指针的简单实现
(1)auto_ptr 的实现
template <class T>class AutoPtr{public:AutoPtr(T* ptr):_ptr(ptr){}AutoPtr(AutoPtr<T>& ap):_ptr(ap._ptr){_ptr = NULL;}AutoPtr<T>& operator=(AutoPtr<T>& ap){if (_ptr != ap._ptr){if (_ptr){delete _ptr;_ptr = ap._ptr;ap._ptr = NULL;}}return *this;}~AutoPtr(){if (_ptr){delete _ptr;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}protected:T* _ptr;};
根据auto_ptr的原理我们能明白,如果按以下的写法:
AutoPtr<int>ap1(new int);AutoPtr<int>ap2(ap1);
我们会发现同一块内存释放了两次,程序会奔溃。如图:
ap1 程序一样会崩溃,原因还是 ap1 被夺走管理权,所以这种编程思想及其不符合C++思想,所以它的设计思想就是有一定的缺陷。
因此,一般不推荐使用 auto_ptr 智能指针。
template<class T>class ScopedPtr{public:ScopedPtr(T*_ptr):_ptr(ptr){}~ScopedPtr(){delete _ptr;}T &operator*(){return *_ptr;}T*operator->(){return _ptr;}protected:ScopedPtr(ScopedPtr<T>& s);ScopedPtr<T> operator=(ScopedPtr<T>& s);protected:T*_ptr;};
并且只声明不实现,这样就实现了 防拷贝 的原理。
protected:ScopedPtr(ScopedPtr<T>& s);ScopedPtr<T> operator=(ScopedPtr<T>& s);
template<class T>class SharePtr{public:SharePtr(T* ptr):_ptr(ptr), _refCount(new int(1)){}~SharePtr(){Release(); }inline void Release(){if (--*_refCount == 0){delete _ptr;delete _refCount;_ptr = NULL;_refCount = NULL;}}T &operator*(){return *_ptr;}T*operator->(){return _ptr;}SharePtr(const SharePtr<T>& sp):_ptr(sp._ptr), _refCount(sp._refCount){++(*_refCount);}SharePtr<T>&operator=(const SharePtr<T>&sp){if (_ptr != sp._ptr){Release();_ptr = sp._ptr;_refCount = sp._refCount;++(*_refCount);}return *this;}protected:T* _ptr;int* _refCount;};
share_ptr 使用时应该注意,在实例化后delete时,SharePtr<int>sp1<new int> 与 SharePtr<string>sp1<newstring[20]>的不同。前者是正确的,而后者就会使程序奔溃,因为后者会多开4个字节的空间,导致释放发生错误。
如图所示,若使用delete,则会造成内存泄露。因此,要使用 share_array 中的 operator[ ],用delete[ ] 来释放。
share_ptr 因为它采用引用计数的思想,所有它是功能较为完善的,但是 share_ptr 还是有缺陷的,例如在解决 循环引用 问题上。
三.循环引用
struct Node{shared_ptr<Node> _prev;shared_ptr<Node> _next;~Node(){cout << "~Node():" << this << endl;}int data;};void FunTest(){shared_ptr<Node> cur(new Node);shared_ptr<Node> next(new Node);cur->_next = next;next->_prev = cur;cout << "cur.use_count:"<<cur.use_count() << endl;cout << "next.use_count:"<<next.use_count() << endl;}int main(){FunTest();return 0;}
运行结果:
可以看到 shared_ptr 的使用使得一块空间有两个对象管理,即头个结点的_next域和下一个指针共同管理,或者又头一个指针和第二个结点的_ptrv域共同管理所以其_refCount=2,这就是我们所谓的 循环引用 问题。
如图所示,这里导致的问题就是内存泄漏,这段空间一直都没有释放,现在很明显引用计数在这里就不是很合适
了,但是shared_ptr除了这里不够完善,其他功能还是很不错的,所以这里补充一个week_ptr,来解决其循环引用问题,接下来我们看最后一个智能指针week_ptr。
- C++ 智能指针——简单实现以及循环引用问题
- C++ — 智能指针的简单实现以及循环引用问题
- [C++] 智能指针与循环引用
- c++ 智能指针及 循环引用问题
- c++ 智能指针及 循环引用问题
- c++ 智能指针及 循环引用问题
- 智能指针 -- 循环引用
- C++-智能指针——简单实现分析
- C++ 智能指针(及循环引用问题)
- 智能指针的实现--使用引用计数实现以及原理
- 【C++】智能指针auto_ptr的简单实现
- 智能指针和引用计数以及String的C++实现
- c++—智能指针
- C++ 引用计数技术及智能指针的简单实现
- C++ 引用计数技术及智能指针的简单实现
- C++ 引用计数技术及智能指针的简单实现
- C++ 引用计数技术及智能指针的简单实现
- C++ 引用计数技术及智能指针的简单实现
- 试一试
- 推荐算法
- Sublime Text 3 快捷键总结(拿走)
- H5面试---Doctype作用
- 图像处理学习笔记(五):Harris角点检测
- C++ 智能指针——简单实现以及循环引用问题
- iOS开发证书与配置文件的使用
- Spring Cloud Config
- Building a Space Station (Kruskal算法)
- 微服务之事件驱动的数据管理(五)
- 用mobx-react框架wukong撸个电影网站
- rpc
- 用Unity2017做一个简易的CardBoardVR应用
- Java序列化与反序列化