赞
踩
最近在书中看到关于智能指针的描述,由于之前没有使用过智能指针,便通过调试源代码(源代码的实现有点杂乱,并不能以最简单直观的方式呈现)了解原理后,以简单直接的方式写了一个shared_ptr指针类。
关于shared_ptr指针的几点介绍:
1.共享指针在拷贝函数中拷贝已有的指针对象参数地址达到共享数据(简单的说就是一块类对象地址由多个指针同时指向并且使用);
2.共享指针内部通过计数形式来记录共享调用类对象内存的次数(创建共享指针对象时计数为1,每被拷贝一次(赋值给别的新对象)计数加1),每释放一个共享指针对象计数减1,当指针计数为0时释放共享调用类对象内存;
3.shared_ptr类共享指针内存及共享计数内存在没有通过手动释放的情况下,将会通过虚拟析构函数来做内存释放工作。
下面贴上代码:
template<typename _Tp> class new_allocator//采用了模板类特有的内存分配类,保证分配产生碎片变少的同时并且提高运行效率 { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; typedef _Tp value_type; template<typename _Tp1> struct rebind { typedef new_allocator<_Tp1> other; }; new_allocator() throw() { } new_allocator(const new_allocator&) throw() { } template<typename _Tp1> new_allocator(const new_allocator<_Tp1>&) throw() { } ~new_allocator() throw() { } pointer address(reference __x) const { return &__x; } const_pointer address(const_reference __x) const { return &__x; } // NB: __n is permitted to be 0. The C++ standard says nothing // about what the return value is when __n == 0. pointer allocate(size_type __n, const void* = 0) { /*if (__builtin_expect(__n > this->max_size(), false)) __throw_bad_alloc();*/ return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); } // __p is not permitted to be a null pointer. void deallocate(pointer __p, size_type) { ::operator delete(__p); } size_type max_size() const throw() { return size_t(-1) / sizeof(_Tp); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 402. wrong new expression in [some_] allocator::construct void construct(pointer __p, const _Tp& __val) { ::new((void *)__p) _Tp(__val); } #ifdef __GXX_EXPERIMENTAL_CXX0X__ template<typename... _Args> void construct(pointer __p, _Args&&... __args) { ::new((void *)__p) _Tp(forward<_Args>(__args)...); } #endif void destroy(pointer __p) { __p->~_Tp(); } }; template<typename _Tp> class allocator: public new_allocator<_Tp> { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; typedef _Tp value_type; template<typename _Tp1> struct rebind { typedef allocator<_Tp1> other; }; allocator() throw() { } allocator(const allocator& __a) throw() : __glibcxx_base_allocator<_Tp>(__a) { } template<typename _Tp1> allocator(const allocator<_Tp1>&) throw() { } ~allocator() throw() { } // Inherit everything else. }; class Ref_count_base/* 指针计数管理 */ { public: Ref_count_base():m_ncount(0) { } long GetCount()//获取当前计数 { return m_ncount; } int ResetCount(int nAdd)//设置当前计数 1. 计数增加1 ,0. 计数减少1 { if (1 == nAdd) { ++m_ncount; } else { --m_ncount; } return m_ncount; } private: long m_ncount;//计数变量 }; template <typename _Ty> class Point_Base/* 在这里做指针计数与数据对象的结合并且都是采用动态分配的方式(通过使用地址)达到数据共享 */ { public: Point_Base() { ref_count = 0; } typedef _Ty* pointer; typedef _Ty& reference; protected: pointer m_obj;//共享类指针对象 Ref_count_base* ref_count;//计数类指针对象 }; template <typename Pointer> class Test_Pointer : public Point_Base<Pointer>//模板指针调用类 { typedef Test_Pointer<Pointer> test_pointer; typedef Pointer* pointer; typedef Pointer& reference; typedef allocator<Pointer> alloc_type; public: virtual ~Test_Pointer()//每次类退出前会执行一次析构函数 { if (!ref_count)/* 已经释放的情况下直接返回 */ { return ; } int ncount = ref_count->ResetCount(0); if (0 == ncount && 0 != m_obj)//如果计数为0而且共享类指针还没有释放,那么这个共享指针没被共享和计数指针一起释放掉 { m_alloc.deallocate(m_obj,sizeof(Pointer) * m_nSize); delete ref_count; } } Test_Pointer():m_nCritical(0),m_nCriticalRun(1),m_nSize(1)//无参数构造函数 分配一个共享类内存 { if (0 == ref_count) { ref_count = new Ref_count_base; } ref_count->ResetCount(1); m_obj = m_alloc.allocate(1); } template<class _Ux> explicit Test_Pointer(_Ux *_Px):m_nCritical(0),m_nCriticalRun(1)//有参数构造函数 根据输入的数量进行分配内存 { if (0 == ref_count) { ref_count = new Ref_count_base; } ref_count->ResetCount(1); m_obj = m_alloc.allocate(*_Px); m_nSize = *_Px; } pointer operator->() /* 增加临时临界区,在多个线程中保证智能指针数据同步,关于调用类对象的数据需要在线程中增加真正的临界区来同步化 */ { if (1 == m_nCriticalRun) { int nRun = m_nCritical; ++m_nCritical; while (nRun != 0 && nRun != m_nCritical) ; --m_nCritical; } return m_obj; } Test_Pointer(test_pointer& _Other)//复制构造函数 { *this = _Other; ref_count->ResetCount(1); } void SetCritical(int nRun);//调用共享类成员数据保护临界区 1. 启动 0. 不启动 默认1(在多线程情况下可以看出效果) void Reset(); template<class _Ux> void Reset(_Ux *_Px)//把共享计数减一后 ,分配新的共享类内存 { if (ref_count && 0 < ref_count->GetCount() && 0 != m_obj) { ref_count->ResetCount(0); if (0 == ref_count->GetCount())/* 如果在共享指针计数减一为0的情况(属于没有在别的地方被使用) ,释放共享指针 和共享指针计数 */ { m_alloc.deallocate(m_obj,sizeof(Pointer) * m_nSize); delete ref_count; } } ref_count = new Ref_count_base; ref_count->ResetCount(1); m_obj = m_alloc.allocate(*_Px); m_nSize = *_Px; } private: alloc_type m_alloc;//内存分配 volatile int m_nCritical;//临界区 volatile int m_nCriticalRun;//临界区是否运行 int m_nSize;//共享类对象内存大小(个数) }; template <typename Pointer> inline void Test_Pointer<Pointer>::SetCritical(int nRun) { m_nCriticalRun = nRun; } template <typename Pointer> inline void Test_Pointer<Pointer>::Reset()/* 调用无参数Reset 把共享指针计数减一 并且把共享指针计数与共享指针赋值为0 */ { if (ref_count && 0 < ref_count->GetCount() && 0 != m_obj) { ref_count->ResetCount(0); if (0 == ref_count->GetCount())/* 如果在共享指针计数减一为0的情况(属于没有在别的地方被使用) ,释放共享指针 和共享指针计数 */ { m_alloc.deallocate(m_obj,sizeof(Pointer) * m_nSize); delete ref_count; } m_obj = 0; ref_count = 0;/* 因为已经脱离了上一个共享指针,所以共享指针 和共享指针计数都指向空 */ m_nSize = 0; } }
使用方法:
Test_Pointer<int> testint(new int(2));
Test_Pointer<int> testint1 = testint;
Test_Pointer<int> testint2 = testint1;
Test_Pointer<int> testint3 = testint;//指向到此处可以看到4个类对象共享类指针地址与共享计数相同
testint.Reset();//共享计数减一 并且共享类指针地址与共享计数地址赋值为0
testint1.Reset(new int(4));//共享计数减一 并且共享类指针地址与共享计数地址赋值为0 , 然后分配新的共享类指针内存 与 共享计数
testint1.SetCritical(0);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。