标签:智能指针简单实现
很多人都误以为智能指针是一个指针,其实不然,智能指针不是指针,智能指针是一个模板,由智能指针实例化出来的的对象具有和常规指针相似的行为,但是他能够自动的释放所指向的对象,所以我们称之为智能指针。如果我们用普通指针来创建一个指向某个对象的指针,那么我们最后必须要手动释放这块空间,而智能指针它是一个类,它释放空间是通过析构函数完成的,正是由于有了这一层封装机制,所以智能指针才能够管理一个对象的生命周期。(定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。这样的方法称为RAII)
起初在C++标准库里面是没有智能指针的,直到C++11中才加入了shared_ptr和unique_ptr,weak_ptr。最早的智能指针在Boost库里面,Boost是为C++标准库提供扩展的一些C++程序的总称,由Boost社区组织开发维护。
1、auto_ptr
auto_ptr在STL中早就存在了,auto_ptr是通过权限转移的方式来防止值拷贝所带来问题,所谓权限转移就是说开辟的动态内存任何时刻只能由一个指针指向。
下面通过实现自己的AutoPtr来剖析一下auto_ptr。现在已经不用aotu_ptr了,常用的是scoped_ptr和shared_ptr.
<span style="font-size:14px;">template<typename T> class AutoPtr //AutoPtr是一个类模板,不是指针类型 { public: AutoPtr(T* ptr=0); AutoPtr(AutoPtr<T>& ap); AutoPtr<T>& operator=(AutoPtr<T>& ap); T* Get(); T* Release(); void Reset(T* ptr=0); T& operator*(); T* operator->(); ~AutoPtr(); private: T* _ptr; }; template<typename T> T* AutoPtr<T>::Get() { return _ptr; } template<typename T> T* AutoPtr<T>::Release() { T* tmp = _ptr; _ptr = NULL; return tmp; } template<typename T> void AutoPtr<T>::Reset(T* ptr = 0) { delete _ptr; _ptr = ptr; ptr = NULL; } template<typename T> AutoPtr<T>::AutoPtr(T* ptr=0) :_ptr(ptr){} template<typename T> AutoPtr<T>::AutoPtr(AutoPtr<T>& ap) //auto_ptr采用权限转移的方式,确保始终只有一个指针指向这块空间 { _ptr = ap._ptr; ap._ptr = NULL; //权限转移 } template<typename T> AutoPtr<T>& AutoPtr<T>::operator=(AutoPtr<T>& ap) { delete _ptr; _ptr = ap._ptr; ap._ptr = NULL; //权限转移 return *this; } template<typename T> T& AutoPtr<T>::operator*() { return *_ptr; } template<typename T> T* AutoPtr<T>::operator->() //有特殊处理 { return _ptr; } template<typename T> AutoPtr<T>::~AutoPtr() { if (_ptr != NULL) { delete _ptr; _ptr = NULL; } }</span><span style="font-size: 19px;"> </span>
下面我们先来介绍boost库中的几种常用的智能指针,由于boost库不是C++标准库,所以我们在使用boost中的智能指针之前先要下载一个boost库,并把它包含到C++标准库中。
1、scoped_ptr
由于auto_ptr的行为与真正的指针有很大区别,尤其是权限转移这种方法。为了防止值拷贝带来的问题,所以scoped_ptr从根本上就不允许拷贝和赋值(防赋值、防拷贝)。
template<typename T> class ScopedPtr //防拷贝,防赋值,使得scopedptr看起来更像一个指针类型,但实际上scopedptr是一个类模板 { public: explicit ScopedPtr(T* ptr); T& operator*(); T* operator->(); ~ScopedPtr(); T* Get() const; void Reset(T *p=0); void Swap(ScopedPtr<T>& sp); protected: ScopedPtr(const ScopedPtr<T>& sp); //将拷贝和赋值运算符声明为保护,防赋值、防拷贝 ScopedPtr<T>& operator=(const ScopedPtr<T>& ap); private: T* _ptr; }; template<typename T> T* ScopedPtr<T>::Get() const { return _ptr; } template<typename T> void ScopedPtr<T>::Reset(T *p = 0) { delete _ptr; _ptr = p; p = NULL; } template<typename T> void ScopedPtr<T>::Swap(ScopedPtr<T>& sp) { swap(_ptr,sp._ptr); } template<typename T> ScopedPtr<T>::ScopedPtr(T* ptr) :_ptr(ptr) {} template<typename T> T& ScopedPtr<T>::operator*() { return *_ptr; } template<typename T> T* ScopedPtr<T>::operator->() //有特殊处理 { return _ptr; } template<typename T> ScopedPtr<T>::~ScopedPtr() { if (NULL!= _ptr) { delete _ptr; _ptr =NULL; } }
2、scoped_array
scoped_array是用来管理数组的。
<span style="font-size:14px;">template<typename T> class ScopedArray { public: ScopedArray(T* ptr); ~ScopedArray(); T& operator[](size_t index); void Reset(T* ptr=0); T* Get() const; protected: ScopedArray(const ScopedArray<T>&); ScopedArray<T>& operator=(const ScopedArray<T>&); private: T* _ptr; }; template<typename T> void ScopedArray<T>::Reset(T* ptr = 0) { if (_ptr != ptr||_ptr==NULL) { delete[] _ptr; _ptr = ptr; ptr = NULL; } } template<typename T> T* ScopedArray<T>::Get() const { return _ptr; } template<typename T> ScopedArray<T>::ScopedArray(T* ptr) :_ptr(ptr) {} template<typename T> ScopedArray<T>::~ScopedArray() { if (NULL != _ptr) { delete[] _ptr; _ptr = NULL; } } template<typename T> T& ScopedArray<T>::operator[](size_t index) { return _ptr[index]; }</span><span style="font-size: 24px;"> </span>
3、shared_ptr
shared_ptr允许拷贝和赋值,其底层实现是以"引用计数"为基础的,通过引用计数来控制空间的释放,当一块空间创建时引用计数为1,当有新的指针指向这块空间时,引用计数加1,反之减1,直到引用计数减为0时才真的释放这块空间。所以说shared_ptr更像一个指针。
template<typename T> class SharedPtr //采用引用计数,实现一个可以有多个指针指向同一块内存的类模板,SharedPtr是类模板,不是智能指针类型 { public: SharedPtr(T* ptr); SharedPtr(const SharedPtr<T>& sp); SharedPtr<T>& operator=(SharedPtr<T> sp); T& operator*(); T* operator->(); ~SharedPtr(); int Count() { return *_pCount; } private: void Release() { if (--(*_pCount) == 0) { delete _ptr; delete _pCount; _ptr = NULL; _pCount = NULL; } } private: T* _ptr; int* _pCount; //指向引用计数的空间 }; template<typename T> SharedPtr<T>::SharedPtr(T* ptr) :_ptr(ptr) , _pCount(new int(1)){} template<typename T> SharedPtr<T>::SharedPtr(const SharedPtr<T>& sp) { _ptr = sp._ptr; _pCount= sp._pCount; ++(*_pCount); } template<typename T> SharedPtr<T>& SharedPtr<T>::operator=(SharedPtr<T> sp) { std::swap(sp._ptr,_ptr); std::swap(sp._pCount,_pCount); return *this; } template<typename T> T& SharedPtr<T>::operator*() { return *_ptr; } template<typename T> T* SharedPtr<T>::operator->() { return _ptr; } template<typename T> SharedPtr<T>::~SharedPtr() { Release(); }
4、shared_array
shared_array也是管理数组的。
<span style="font-size:14px;">template<typename T> class SharedArray { public: SharedArray(T* ptr); ~SharedArray(); SharedArray(const SharedArray<T>& sp); SharedArray<T>& operator=(SharedArray<T> sp); T& operator[](size_t index); private: T* _ptr; int* _pCount; }; template<typename T> SharedArray<T>::SharedArray(T* ptr) :_ptr(ptr) , _pCount(new int(1)) {} template<typename T> SharedArray<T>::~SharedArray() { if (--(*_pCount) == 0) { delete[] _ptr; _ptr = NULL; delete _pCount; _pCount = NULL; } } template<typename T> SharedArray<T>::SharedArray(const SharedArray<T>& sp) { _ptr = sp._ptr; _pCount = sp._pCount; ++*pCount; } template<typename T> SharedArray<T>& SharedArray<T>::operator=(SharedArray<T> sp) { swap(_ptr,sp._ptr); swap(_pCount,sp._pCount); return *this; } template<typename T> T& SharedArray<T>::operator[](size_t index) { return _ptr[index]; }</span><span style="font-size: 24px;"> </span>
本文出自 “11132019” 博客,转载请与作者联系!
标签:智能指针简单实现
原文地址:http://11142019.blog.51cto.com/11132019/1846846