首先了解shared_ptr毫无疑问的是智能指针的一种,智能指针是为了解决在大型代码里无法不好控制指针的问题,例如:在类里面如果出现了动态开辟出来的空间,有一个指针指向这块空间,如果在相应的作用范围之内没有将其delete掉会造成内存的泄漏,所以这样就必须手动的对这一块空间进行释放,但是这非常不利于我们的工作,所以我们就引入了智能指针,它是一个类,它的作用范围结束就自动释放了,所以这样达到了智能的管理这一块空间。所以shared_ptr也自然地拥有了上面的特性和功能,现在就对shared_ptr做一个较为深层次的理解并掌握它的使用。
Boost库的智能指针(ps:新的C++11标准中已经引入了unique_ptr/shared_ptr/weak_ptr),所以言下之意就是在使用unique_ptr/shared_ptr/weak_ptr之前都需要进行boost编译,所以这样也不方便使用,在c++11中将boost也纳入了标准,这样就可以在较高版本的编译器下直接使用这些智能指针。所以shared_ptr可以在我的编译器下直接使用而不需要编译,因为我的编译器是13版的。
SharedPtr,利用字符串相似的写时拷贝方式实现,让创建的对象维护同一块空间,并且用一个int* _pcount对引用这块空间的次数进行计数。
现在先对shared_ptr进行一个模拟的实现:
template <typename T>
class SharedPtr //相似于string类的写实拷贝,如果用深拷贝的方式达不到指针的效果,p1=p2,不能让p1和p2同时管理一块空间
{
public:
SharedPtr( T* ptr )
:_pcount( new int (1))
, _ptr( ptr)
{
}
~SharedPtr()
{
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
}
SharedPtr( const SharedPtr & s)
:_ptr( s._ptr)
, _pcount( s._pcount)
{
++(*_pcount);
}
/* 这种写法较为复杂
SharedPtr& operator=(const SharedPtr& s)//分三种情况,自己给自己赋值,两对象指向同一空间,指向不同的空间
{
if (_ptr != s._ptr)
{
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
_ptr = s._ptr;
_pcount = s._pcount;
++(*_pcount);
}
return *this;
}
*/
SharedPtr& operator=( const SharedPtr s )//这种写法较为简单,并且这样写法一致性好,在自赋值,指向同一块空间赋值,指向不同空间的赋值都满足
{
swap(_ptr, s._ptr);
swap(_pcount, s._pcount);
return *this ;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
protected:
T* _ptr;
int* _pcount;
};
上面是实现了shared_ptr的几个基本函数,shared_ptr无疑的要实现成模板类,因为它在运用时可以是不同类型的指针,同时它还要尽力的模仿的和原生指针比较相似。
/*****************************************************************/
上面是对shared_ptr的原理进行了分析,现在对shared_ptr在使用时要注意的问题进行分析(首先要了解shared_ptr在使用时会发生循环引用和定制删除器这两个要点)
- 循环引用问题
shared_ptr的循环引用问题及其解决方法:(形成循环引用的原因是因为cur最后释放会依赖于next->_prev的释放,而next的释放又依赖于cur->_next的释放,所以形成无法释放的局面)
weak_ptr不完全增加引用计数,打破shared_ptr的死穴
2.定制删除器:
定置删除器:在使用share_ptr时,因为shared_ptr只能管理用new开辟出来的空间,因为shared_ptr析构函数的实现是依靠delete _ptr实现,所以对于malloc和fopen等操作并不能做到析构,如果不定置删除器将会导致程序的崩溃,因为malloc需要用free来解决,fopen需要用fclose来解决(利用仿函数这个方法来实现定置删除器)利用仿函数来解决问题,仿函数是一个类,对象可以像一个函数一样调用,它是一个空类。
下面实现定制删除器的使用:
#include<iostream>
#include<memory>
using namespace std;
template <typename T,typename Del>
class SharedPtr
{
public:
void Release()
{
if (--(*_pcount) == 0)
{
_del(_ptr);
delete _pcount;
}
}
SharedPtr(T* ptr)
:_ptr(ptr)
, _pcount(new int(1))
{
}
~SharedPtr()
{
Release();
}
private:
T* _ptr;
int* _pcount;
Del _del;
};
template <typename T>//定制删除器(new)
struct Del//是个类,可以当作一个模板参数
{
void operator()(T* _ptr)
{
cout << "delete _ptr" << endl;
delete _ptr;
}
};
template <typename T>//定制删除器(malloc)
struct Free
{
void operator()(T* _ptr)//重载(),可以像函数一样使用这个类
{
cout << "Free _ptr" << endl;
free(_ptr);
}
};
template <typename T>//定制删除器(文件)
struct Fclose
{
void operator()(T* _ptr)
{
cout << "Fclose _ptr" << endl;
fclose(_ptr);
}
};
void testDel()
{
SharedPtr<int, Del<int>> sp1(new int(1));
SharedPtr<int, Free<int>> sp2((int*)malloc(sizeof(int)));
FILE* fp = fopen("yxt.txt", "r");
SharedPtr<FILE, Fclose<FILE>> sp3(fp);
}
int main()
{
testDel();
system("pause");
return 0;
}