关于shared_ptr

来源:互联网 发布:旅游大数据应用 编辑:程序博客网 时间:2024/06/06 15:35

 首先了解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在使用时会发生循环引用和定制删除器这两个要点)

  1. 循环引用问题

  shared_ptr的循环引用问题及其解决方法:(形成循环引用的原因是因为cur最后释放会依赖于next->_prev的释放,而next的释放又依赖于cur->_next的释放,所以形成无法释放的局面)


wKiom1cB43WC884mAAAjULCF-fE240.png

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;

}

1 0