1. 程式人生 > >智慧指標例項(引用計數型)

智慧指標例項(引用計數型)

如果在多個類的例項中共享同一塊堆記憶體,指標的操作會相當繁瑣,一不小心就會出現野指標,試想一塊記憶體被其中一個指標釋放了,另外幾個物件的指標仍然指向他的情況,相當可怕!這時候就需要用帶有引用計數的智慧指標管理了!

《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 ) 是可行的!使用時依舊可以表現出多型性。