智慧指標例項(引用計數型)
阿新 • • 發佈:2019-02-01
如果在多個類的例項中共享同一塊堆記憶體,指標的操作會相當繁瑣,一不小心就會出現野指標,試想一塊記憶體被其中一個指標釋放了,另外幾個物件的指標仍然指向他的情況,相當可怕!這時候就需要用帶有引用計數的智慧指標管理了!
《C++ Primer》上給出了兩種實現方式:
1.利用友元類實現指標計數的管理
class U_Ptr{ friend class HasPtr; int *ip; //共享的資料 size_t use; U_Ptr(int *p) : ip(p), use(1) {} ~U_Ptr() { delete ip; } }; class HasPtr{ public: HasPtr(int *p, int i) : ptr(new U_Ptr(p)), val(i) { } HasPtr(const HasPtr& orig) : ptr(orig.ptr), val(orig.val){ ++ptr->use; } HasPtr& operator= (const HasPtr& rhs); ~HasPtr() { if (--ptr->use == 0) { delete ptr; } } private: U_Ptr *ptr; int val; }; HasPtr& HasPtr::operator= (const HasPtr& rhs){ if (this != &rhs) { if (--ptr->use == 0) { delete ptr; } ++rhs.ptr->use; ptr = rhs.ptr; val = rhs.val; } return *this; }
2.非友元函式實現
class base{ //實際物件 }; class SmartPtr{ public: SmartPtr() : p(0), use(new size_t(1)) {} SmartPtr(const base&); SmartPtr(const SmartPtr& i) : p(i.p), use(i.use) {++*use;} ~SmartPtr() {decr_use();} SmartPtr& operator= (const SmartPtr&); const base* operator->() const { if(p) return p; else throw std::logic_error("unbound base"); //#include <stdexcept> } const base& operator*() const { if(p) return *p; else throw std::logic_error("unbound base"); } private: base* p; size_t* use; void decr_use(){ if (--*use == 0) { delete p; delete use; } } }; SmartPtr& SmartPtr::operator= (const SmartPtr& rhs) { if (this != &rhs) { decr_use(); ++*rhs.use; use = rhs.use; p = rhs.p; } return *this; }
3.版本2的模版型--------參考《C++標準程式庫》 p222
template <class T> class CountedPtr { private: T* ptr; long* count; public: explicit CountedPtr (T* p=0) : ptr(p), count(new long(1)) { } CountedPtr (const CountedPtr<T>& p) throw() : ptr(p.ptr), count(p.count) { ++*count; } ~CountedPtr() throw() { dispose(); } CountedPtr<T>& operator= (const CountedPtr<T>& p) throw() { if (this != &p) { dispose(); ptr = p.ptr; count = p.count; ++*count; } return *this; } T& operator*() throw(){ return *ptr; } T* operator->() throw() { return ptr; } private: void dispose() { if (--*count == 0) { delete ptr; delete count; } } };
對以上有:
如果型別T是一個類,型別L是T的派生類,那麼 CountePtr<T> 和 CountePtr<L> 是兩個不同的型別,拷貝建構函式並不能完成兩者之間的拷貝!
應使用memer function template 來泛化copy construct ,並保留原有正常copy construct,防止編譯器自動生成 。 assignment opertator 同!
PS:CountePtr<T> a(new L ) 是可行的!使用時依舊可以表現出多型性。