产生原由:当你在堆中分配出一块内存,即使用new或者malloc出来的空间,也需要自己手动去调用delete或者free去析构这块空间,但是忘记析构的时候,会产生内存泄漏等问题,此时产生了智能指针来解决此类问题。
智能指针类型:auto_ptr,scoped_ptr,shared_ptr,weak_ptr
1.auto_ptr
属于STL库,包含在#include<memory>
头文件中,用来管理单个堆内存,简单使用但是有许多缺陷
实现auto_ptr
(1)权限转移
template<class T>
class My_autoptr
{
public:
My_autoptr(T*ptr=0)
:_ptr(ptr)
{
ptr = NULL;
}
My_autoptr(My_autoptr<T> & ap)
:_ptr(ap._ptr)
{
ap._ptr = NULL;
}
My_autoptr<T>& operator =(My_autoptr<T>& ap)
{
if (this != &ap)
{
if (_ptr)
{
delete _ptr;
}
_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
~My_autoptr()
{
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}
T &operator*()
{
return *_ptr;
}
T *operator->()
{
return _ptr;
}
private:
T *_ptr;
};
void test()
{
My_autoptr<int>p(new int(123));
My_autoptr<int>p1(p);
My_autoptr<int>p2;
p2 = p1;
}
如图所示:
(2)在AutoPtr的类内加入新的成员变量bool类型的_owner,构造函数中将_owner设置为true,表示对象是指针所指向内存的拥有者。
代码实现
template<class T>
class AutoPtr
{
public:
AutoPtr(T* ptr=0)
:_ptr(ptr)
, _owner(true)
{
ptr = NULL;
}
AutoPtr(AutoPtr<T>& ap)
:_ptr(ap._ptr)
, _owner(true)
{
ap._owner=false;
}
~AutoPtr()
{
if (_owner)
{
delete _ptr;
}
}
AutoPtr<T>&operator=(AutoPtr<T>& ap)
{
if (this != &ap)
{
if (_owner){
delete _ptr;
}
_ptr = ap._ptr;
_owner = true;
ap._owner = false;
}
return *this;
}
T* operator->()
{
return _ptr;
}
T &operator*()
{
return *_ptr;
}
private:
T *_ptr;
bool _owner;
};
void test()
{
AutoPtr<int>p(new int(1));
if(_owner)
{
AutoPtr<int>p1(p);//此时p1为true,p为false
}
*p=2;//当p1作为临时变量退出时调用析构函数,此时p变成了野指针,*p便会报错
}
get()返回当前指针对象
operator*返回指针所指向的内容
operator->返回成员对象
release()清空当前智能指针,返回指针类型
operator=清空当前智能指针并拷贝给新的智能指针
reset()清空当前智能指针,将指针置为空。
2.scoped_ptr
属于boost库,一个类似于auto_ptr,不过scoped_ptr独享所有权,不能进行赋值与拷贝!!!在这里我们只是将赋值运算符重载和operator=重载进行声明不进行定义,因此此智能指针功能不全。
代码实现:
template<class T>
class ScopedPtr
{
public:
ScopedPtr(const T*ptr = 0)
:_ptr(ptr)
{
ptr = NULL;
}
~ScopedPtr()
{
if (_ptr)
delete _ptr;
}
T*operator ->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
T* get()
{
return _ptr;
}
void reset(T*p=0)
{
if(_ptr!=p)
{
delete _ptr;
_ptr=p;
}
}
//防拷贝
//1.只声明不实现
//2.声明成私有保护
private:
ScopedPtr(const ScopedPtr<T>&);
ScopedPtr<T>& operator=(const ScopedPtr<T>&);
protected:
T *_ptr;
};
通过代码我们可以看出并没有实现operator=以及拷贝构造函数,便不会导致所有权转移等问题
3.shared_ptr
属于boost库,包含头文件#include<boost/smart_ptr.hpp>
,用于管理单个堆内存对象,shared_ptr做到了共享所有权,同时内部使用引用计数的方式,_refcount初始构造为1,当_refcount==0时,调用析构函数。
shared_ptr最安全的分配和使用动态内存的方式是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr
例如:
shared_ptr<int>p1=make_shared<int>(42)//指向一个值为42的int型的shared_ptr
shared_ptr<string>p2=make_shared<string>(10,'9');//指向一个值为"9999999999"的string
首先来说明shared_ptr存在的循环引用的问题
#include<boost/shared_ptr.hpp>
#include<boost/weak_ptr.hpp>
using namespace boost;
struct ListNode
{
shared_ptr<ListNode> _prev;
shared_ptr<ListNode> _next;
~ListNode()
{
cout<<"~ListNode()"<<endl;
}
};
void test()
{
shared_ptr<ListNode>p1(new ListNode());
shared_ptr<ListNode>p2(new ListNode());
cout<<"p1->count:"<<p1.use_count()<<endl;
cout<<"p2->count:"<<p2.use_count()<<endl;
p1->_next=p2;
p2->_prev=p1;
cout<<"p1->count:"<<p1.use_count()<<endl;
cout<<"p2->count:"<<p2.use_count()<<endl;
}
当你实现此段代码后,你将会发现p1与p2的计数器都会是2;当你选择析构其中一个指针的时候便会依赖与另外一个,此时便会产生一个循环,且两者都不会进行析构,造成内存泄漏。
如何能正常解决循环引用的问题,此时我们便加入weak_ptr弱引用智能指针。
4.weak_ptr
weak_ptr指向shared_ptr指向对象的内存,但不共享这块内存,也没有重载operator*和operator->,他的构造不会使指针引用计数的增加。
weak_ptr w
use_count():可以观测shared_ptr的引用计数;
expired():若与之对应的use_count()为0,返回true,否则返回false;
lock():若expired为true,返回一个空shared_ptr;否则返回一个指向w的对象的shared_ptr;
如何通过weak_ptr来解决shared_ptr的循环引用问题
代码实现:
struct Delete//由于shared_ptr存在的循环引用导致指针不能被自动析构,此时我们定制删除器
{
template<class T>
void operator()(T* ptr)
{
delete ptr;
}
};
template<class T>
class WeakPtr;
template<class T, class D= Delete>
class SharedPtr
{
friend class WeakPtr<T>;
public:
SharedPtr(T*ptr = 0,D del= Delete())
:_ptr(ptr)
, _refCount(new int(1))
,_del(del)
{}
SharedPtr(const SharedPtr<T, D>& sp)
:_ptr(sp._ptr)
,_refCount(sp._refCount)
{
++(*_refCount);
}
SharedPtr<T, D>& operator=(const SharedPtr<T, D>& sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_refCount = sp._refCount;
++(*_refCount);
}
return *this;
}
~SharedPtr()
{
Release();
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
void Release()
{
if (--(*_refcount) == 0)
{
if(_ptr)
delete _ptr;
_ptr = NULL;
}
delete _refcount;
}
private:
T *_ptr;
int* _refCount;
D _del;
};