所谓的智能指针就是智能/自动化的管理指针所指向的动态资源的释放。
智能指针的产生是由于C++没有内存的自动回收机制,每次new出来的空间都需要收到的delete,而在个别情况下,总是无法及时的delete,或者异常导致程序提早退出,造成内存泄漏。于是弥补上述不足的智能指针应用而生。
智能指针的发展可分为三个阶段
(1)auto_ptr c++98
(2)scoped_ptr/shared_ptr/weak_ptr boost库
(3)unique_ptr/shared_ptr/weak_ptr c++11
设计思想
auto_ptr实际上是管理权限的转移,此设计本身带有缺陷,不宜使用。
template<class T>
class Auto_ptr
{
public:
Auto_ptr(T* ptr)
:_ptr(ptr)
{}
Auto_ptr(Auto_ptr<T>& ap)
{
ap._ptr = NULL;
}
Auto_ptr<T>& operator=(Auto_ptr<T>& ap)
{
if(_ptr != ap._ptr)
{
delete _ptr;
_ptr = NULL;
_ptr = ap._ptr;
ap._ptr = NULL;
}
return *this;
}
~Auto_ptr()
{
if(_ptr)
{
delete _ptr;
}
}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
private:
T* _ptr;
};
通过管理权的转移,避免了同一块空间被释放两次,的问题,但同时,原有指针也失去了对该空间的操作权限,所以不建议使用该方法。
scoped_ptr又叫 守卫指针,用来防止拷贝,可以解决Auto_ptr的问题。
解决的方法:
(1)拷贝构造和赋值运算符的操作可以只声明,不定义。
(2)将声明为私有,防止定义。
template<class T>
class Scoped_ptr
{
public:
Scoped_ptr(T* ptr)
:_ptr(ptr)
{}
~Scoped_ptr()
{
if(_ptr)
{
delete _ptr;
}
}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
private:
Scoped_ptr<T>& operator=(Scoped_ptr<T>& sp);
Scoped_ptr(Scoped_ptr<T>& sp);
private:
T* _ptr;
};
指针功能明显受到限制,后来人们就不用了;于是行的智能指针诞生了。
shared_ptr采用了引用计数的思想,为需要拷贝和福祉的指针开启另一个空间。
temeplate<class T>
class Shared_ptr
{
public:
Shared_ptr(T* ptr)
:_ptr(ptr)
,_ref(new int(1))
{}
Shared_ptr(Shared_ptr<T>& sp)
:_ptr(sp.ptr)
,_ref(sp.ref)
{
(*_ref)++;
}
Shared_ptr<T>& operator=(Shared_ptr<T>& sp)
{
if(_ptr != sp._ptr)
{
if(--(*_ref) == 0)
{
delete _ptr;
deelte _ref;
}
delete _ptr;
_ptr = sp._ptr;
_ref = sp._ref;
(*_ref)++;
}
return *this;
}
~Shared_ptr()
{
if(--(*_ref)==0)
{
delete _ptr;
delete _ref;
}
}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return _*ptr;
}
int Getref()
{
return *_ref
}
T* Getptr()
{
return _ptr;
}
protected:
T* _ptr;
int* _ref;
};
上面的代码虽然简单的实现引用计数版的简化版智能指针Shared_ptr;但是存在着一下问题,
(1)引用计数更新存在着线程安全。
(2)循环引用的问题。
(3)定制删除器。
解决循环引用的问题,需要一个弱指针。
struct ListNode
{
//WeakPtr<ListNode> _prev;
//WeakPtr<ListNode> _next;
SharedPtr<ListNode> _prev;
SharedPtr<ListNode> _next;
~ListNode()
{
cout << "~ListNode()" << endl;
}
};
void TestCycleRef()
{
SharedPtr<ListNode> cur = new ListNode;
SharedPtr<ListNode> next = new ListNode;
cout << "cur->Coun t:" << cur.RefCount() << endl;
cout << "next->Coun t:" << next.RefCount() << endl;
cur->_next = next;
next->_prev = cur;
cout << "cur->Coun t:" << cur.RefCount() << endl;
cout << "next->Coun t:" << next.RefCount() << endl;
}
cur与next的引用计数均为2,且均无法释放,改为weak_ptr,(不增加引用计数)
template<class T>
class WeakPtr
{
public:
WeakPtr()
:_ptr(NULL)
{}
WeakPtr(const SharedPtr<T>& sp)
:_ptr(sp.GetPtr())
{}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
};
如此解决了循环引用的问题。