很多人都误以为智能指针是一个指针,其实不然,智能指针不是指针,智能指针是一个模板,由智能指针实例化出来的的对象具有和常规指针相似的行为,但是他能够自动的释放所指向的对象,所以我们称之为智能指针。如果我们用普通指针来创建一个指向某个对象的指针,那么我们最后必须要手动释放这块空间,而智能指针它是一个类,它释放空间是通过析构函数完成的,正是由于有了这一层封装机制,所以智能指针才能够管理一个对象的生命周期。(定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。这样的方法称为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