智能指针是一个行为类似指针的对象。我们在使用堆内存时,都需要及时地进行释放,避免造成内存泄漏。但我们偶尔也会忘记将其释放掉,从而造成内存泄漏。并且,在释放的时候,我们可能对某一个指针进行了重复释放,导致程序崩溃的问题。为了能够解决这些问题,从而有了智能指针的设计。
智能指针一共有四种,分别是shared_ptr、unique_ptr、weak_ptr、auto_ptr。auto_ptr是C++98提供的解决方案,C++11这个版本提供了shared_ptr、unique_ptr、weak_ptr三种智能指针,在使用的时候需要包含头文件memory。智能指针在创建的对象过期的时候,析构函数会自动调用delete来释放内存。在用到智能指针的过程中需要注意到由于智能指针是一个对象,不是一个指针,因此不能使用普通指针构造智能指针。
1.shared_ptr智能指针
shared_ptr使用了引用计数,在进行拷贝和赋值的时候,会使得指针指向相同的内存,使得引用计数+1,进行析构或者重新赋值(重新赋值使得指针的指向发生改变,不再指向原来的内存地址)的时候,引用计数-1。直到引用计数为0的时候,才会对内存进行释放。根据这些特点,我们可以自己模拟实现一个简单的shared_ptr智能指针。
#include <iostream>
#include <map>
#include <memory>
using namespace std;
template<typename T>
class smartPtr
{
private:
T *_ptr;
static map<T*,int> _num;
public:
smartPtr(T *p)
{
_ptr = p;
if(_num.find(p) != _num.end())
{
_num[p]++;
}
else
{
_num.insert(make_pair(p,1));
}
}
smartPtr(const smartPtr&src)
{
_ptr = src._ptr;
_num[src._ptr]++;
}
~smartPtr()
{
if(--_num[_ptr] == 0)
{
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
};
template<typename T>
map<T*,int> smartPtr<T>::_num = map<T*,int>();
2.weak_ptr智能指针
在实际使用shared_ptr智能指针的时候,可能会出现循环引用的情况,并且shared_ptr是一个强引用,强智能指针的交叉引用,会导致在释放的时候,由于指针互相指向对方,导致无法被释放掉,计数器始终停留在1。为了解决这个问题,而实现了weak_ptr弱智能指针。
weak_ptr是一个弱引用,它并不会引起引用计数的变化。弱智能指针无法直接投入使用,如果需要使用的话,就转为强智能指针。这时候就要用到lock()。
弱智能指针在转化为强智能指针时,有成功和失败两种情况。失败的情况是由于原来的已经被释放,转化为强智能指针之后,无法在map里找到其对应的强智能指针,所以导致失败。