说起智能指针,不少人都不陌生。比方auto_ptr、shared_ptr、unique_ptr、weak_ptr。
依据shared_ptr的功能,自己仿造也实现了个。
对于shared_ptr这样的智能指针,有一个共享的引用计数器来控制指针对象的销毁,当引用计数器变为0时。则销毁指针指向的对象。对于多线程安全问题,我在代码中使用的Interlocked系列的原子操作函数。
在学习过程中,渐渐学会了RAII(Resource Acquisition Is Initialization),慢慢领略到了这样的模式的优点。
直接上代码:
SmartPtr.hpp
#pragma once #include "stdafx.h" #include <assert.h> #include <windows.h> //#define DEBUG_SMARTPTR template<typename T> class SmartPtr; template <typename T> class RefPtr { friend class SmartPtr<T>; explicit RefPtr(T *p) :pointer(p), nUse(0) { assert(pointer); #ifdef DEBUG_SMARTPTR std::cout << "Create Pointer!" << std::endl; #endif } RefPtr(const RefPtr&) { } RefPtr& operator= (const RefPtr & ref) { } ~RefPtr() { #ifdef DEBUG_SMARTPTR std::cout << "Delete Pointer!" << std::endl; #endif assert(pointer); if (pointer != NULL) { delete pointer; pointer = NULL; } } unsigned int AddRefCount() { return InterlockedIncrement((unsigned int*)&nUse); } unsigned int SubRefCount() { return InterlockedDecrement((unsigned int*)&nUse); } bool AddRefCount_lock() { for (;;) { unsigned int temp = nUse; if (temp == 0) { return false; } if (InterlockedCompareExchange((unsigned int *)&nUse, temp + 1, temp) == temp) { return true; } } } volatile unsigned int nUse; T *pointer; }; template<typename T> class SmartPtr { public: explicit SmartPtr(T *pointer) :ptr(new RefPtr<T>(pointer)) { assert(pointer); #ifdef DEBUG_SMARTPTR std::cout << "Create SmartPointer!" << std::endl; #endif ptr->AddRefCount(); } explicit SmartPtr(const SmartPtr<T>& sp) :ptr(sp.ptr) { #ifdef DEBUG_SMARTPTR std::cout << "Copy0 SmartPointer!" << std::endl; #endif ptr->AddRefCount(); } explicit SmartPtr(const SmartPtr<T>* sp) :ptr(sp->ptr) { #ifdef DEBUG_SMARTPTR std::cout << "Copy1 SmartPointer!" << std::endl; #endif ptr->AddRefCount(); } SmartPtr& operator=(const SmartPtr<T>& sp) { if (sp.ptr != ptr) { //注意先加后减,防止指向同对象析构的问题 if (sp.ptr->AddRefCount_lock()) { if (ptr->SubRefCount() == 0) { delete ptr; } ptr = sp.ptr; } } #ifdef DEBUG_SMARTPTR std::cout << "Copy2 SmartPointer!" << std::endl; #endif return *this; } T* operator->() { return GetPtr(); } T* operator->() const { return GetPtr(); } T& operator*() { return *ptr->pointer; } T& operator*() const { return *ptr->pointer; } bool operator!() { return !ptr; } ~SmartPtr() { if (ptr->SubRefCount() == 0) { delete ptr; } #ifdef DEBUG_SMARTPTR std::cout << "Delete SmartPointer!" << std::endl; #endif } int GetRefCount() const { return ptr->nUse; } bool isNull() { return ptr->pointer == NULL; } T* GetPtr() const { assert(ptr->pointer); return ptr->pointer; } //返回对象 T GetValue() const { assert(ptr->pointer); return *ptr->pointer; } private: RefPtr<T> *ptr; }; //兼容const比較 template<typename T> inline bool operator==(const SmartPtr<T>& a,const SmartPtr<T>& b) { return a.GetPtr() == b.GetPtr(); } template<typename T> inline bool operator!=(const SmartPtr<T>& a,const SmartPtr<T>& b) { return a.GetPtr() != b.GetPtr(); }test.cpp
#include "SmartPtr.hpp" #include <iostream> #include <process.h> #define THREADCOUNT 10 typedef struct _PERSON_ { char szName[20]; int nAge; ~_PERSON_() { std::cout << "Person Distructor!"<< std::endl; } }PERSON; SmartPtr<PERSON> g_p(new PERSON{ "g_test", 12 }); unsigned int __stdcall testThread(void *pParam) { SmartPtr<PERSON> sp((SmartPtr<PERSON> *)pParam); g_p = sp; std::cout << sp->nAge << std::endl; return 0; } int _tmain(int argc, _TCHAR* argv[]) { do { HANDLE hThread[THREADCOUNT]; SmartPtr<PERSON> p0(new PERSON{ "Jovi", 12 }); SmartPtr<PERSON> p1(new PERSON{ "Solanin", 13 }); SmartPtr<PERSON> p2(p1); const SmartPtr<PERSON> p3(p1); SmartPtr<PERSON> p4(p3); std::cout << (p3 == p1) << std::endl; std::cout << (p2 == p0) << std::endl; std::cout << (p3 != p1) << std::endl; std::cout << (p2 != p0) << std::endl; p4 = p0; SmartPtr<PERSON> *p = new SmartPtr<PERSON>(p1); for (int i = 0; i < THREADCOUNT; i++) { hThread[i] = (HANDLE)_beginthreadex(NULL, 0, testThread, (void *)p, 0, 0); // WaitForSingleObject(hThread[i], INFINITE); } WaitForMultipleObjects(THREADCOUNT, hThread, TRUE, INFINITE); delete p; } while (0); system("pause"); return 0; }此处的do while(0)仅仅是我想在pause前打印出全部析构函数的输出。
对于基于引用计数器的智能指针,最致命缺点就是循环引用,导致对象被长期占用,无法释放。
以上是我对智能指针的实现和个人看法,如有不对的地方,欢迎指出。