智能指针
1,什么是智能指针?
智能指针实际上是一个类,这个类的对象在构造函数时获取资源,同时在类内部重载 * 和 -> 操作符,用来获取资源。
并在析构函数中执行对资源的释放。
因为C++语言没有内存回收机制,所以总会导致内存泄漏,智能指针可以解决这个问题。
因为这个类的对象是在栈上创建的,那么在程序结束时,销毁类对象自动调用析构函数释放资源,就不会内存泄露了。
2,auto_ptr
中心思想:资源转移
代码实现:
template<class T>
class auto_ptr
{
auto_ptr(T* ptr)
:_ptr(ptr)
{}
T* operator->()//
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
auto_ptr( auto_ptr<T>& a)
{
_ptr = a._ptr;
a.ptr = NULL;
}
auto_ptr<T>& operator=(auto_ptr<T>& a)
{
if (this != &a)
{
delete this->_ptr;
this->_ptr = a._ptr;
a._ptr = NULL;
}
}
~auto_ptr()
{
delete _ptr;
}
private:
T* _ptr;
};
淘汰原因:
1、auto_ptr要求一个对象只能有一个拥有者,严禁一物二主
2、缺少对引用数和数组的支持。
3、不可将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果。(这一条晕死一大片)。
4、auto_ptr在被复制的时候会传输所有权
分析 * 和 -> 重载的意义
设 x 为一个智能指针的对象,那么 *x 就表示operator*(x),返回这个智能指针管理的资源。
对于->号,是用于访问资源中某个成员的,比如,管理的资源是一个结构体指针,访问这个结构体的某个成员时
例如:x->a operator->() ->a ,也就是说先返回返回结构体指针,在访问指定成员。
3,unique_ptr
中心思想:防止拷贝
实现代码:
template<class T>
class unique_ptr
{
public:
unique_ptr(const T* ptr)
:_ptr(ptr)
{}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
~unique_ptr()
{
delete _ptr;
}
protected://protected 使得在类外无法调用,只声明不定义,使得在类中不产生默认函数,也不执行
unique_ptr(unique_ptr<T>& s);
unique_ptr<T> operator=(unique_ptr<T>& s);
private:
T* _ptr;
};
缺点不足:
当我们真正的想要复制一个智能指针的时候,却无法办到了。
4,shared_ptr
中心思想:计数共享
代码实现:
template<class T>
class shared_ptr
{
public:
shared_ptr(T* ptr)
:_ptr(ptr)
, count(new int(1))
{}
T* operator->()
{
return _ptr;
}
T& operator*()
{
return *_ptr;
}
shared_ptr(shared_ptr<T>& a)
{
_ptr = a._ptr;
count = a.count;
++(*count);
}
shared_ptr<T>& operator=(shared_ptr<T>& a)
{
if (this != &a)
{
Release();
_ptr = a._ptr;
count = a.count;
++(*count);
}
}
~shared_ptr()
{
Release();
}
private:
void Release()
{
if (0 == --*(count))//如果*count不是等于0,那也已经减一了
{
delete _ptr;
delete count;
_ptr = NULL;
count = NULL;
}
}
T* _ptr;
int* count;
};
缺点不足:循环引用
循环引用举例代码
struct ListNode
{
shared_ptr<ListNode> _next;
shared_ptr<ListNode> _pre;
int _data;
ListNode(int data)
:_data(data)
, _pre(NULL)
, _next(NULL)
{}
};
int main()
{
shared_ptr<ListNode> cur(new ListNode(1));
shared_ptr<ListNode> next(new ListNode(2));
cur->_next = next;
next->_pre = cur;
return 0;
}
画图分析:
解决方法:weak_ptr
只需要在结构体中将shared_ptr换成 weak_ptr
只需要把Node结点里面的指针定义为weak_ptr类型就好,weak_ptr的构造析构不会影响引用计数的大小,当我们采用这种方式时,cur和next的引用计数始终为1,当我们想销毁时就可以随意操作啦!
struct ListNode
{
shared_ptr<ListNode> _next;
shared_ptr<ListNode> _pre;
int _data;
ListNode(int data)
:_data(data)
, _pre(NULL)
, _next(NULL)
{}
};