1. 程式人生 > >智慧指標的兩種實現(引用計數)

智慧指標的兩種實現(引用計數)

    在微信上看到一篇“C++引用計數及智慧指標的簡單實現”的好文章點選開啟連結,通俗易懂,激起了敲程式碼的興趣,於是用兩種方式實現了簡單的智慧指標(輔助類+SmartPtr類 vs SmartPtr類)。關於什麼是智慧指標以及普通指標所存在的問題以及什麼是引用計數,檢視該文即可(講的很好)點選開啟連結,本文僅列出兩種實現方式的程式碼,希望對大家有所幫助,若存在問題,歡迎指正,謝謝!

方式一:輔助類+SmartPtr類(實現原理如下圖)


#pragma once

#include<iostream>
using namespace std;

//使用輔助類
template<class T>
class SmartPtr;

/*
	輔助類包含:
		1、引用計數器_count;
		2、指向實際空間的指標_ptr;
*/
template<class T>
class Asistant
{
	friend class SmartPtr<T>;
private:
	Asistant(T *ptr) :_count(1), _ptr(ptr)
	{}
	~Asistant(){
		delete _ptr;
		_ptr = NULL;
	}
	int _count;
	T *_ptr;
};

/*
	智慧指標類:(包含)
		1、指向輔助類的指標
*/
template<class T>
class SmartPtr{
public:
	SmartPtr(T *ptr) :_p(new Asistant<T>(ptr))
	{}
	SmartPtr(const SmartPtr<T> &sp){
		_p = sp._p;
		_p->_count++;
	}
	SmartPtr& operator=(const SmartPtr<T> &sp){
		if (this != &sp){
			//處理好原來的關係---->注意:處理好與“前妻”的關係
			if (--(_p->_count) == 0){
				delete _p;         //會先呼叫輔助類的解構函式(釋放實際空間),再釋放輔助類物件空間
			}
			//指向新的輔助空間
			_p = sp._p;
			(_p->_count)++;
		}
		return *this;
	}
	~SmartPtr(){
		if (--(_p->_count) == 0){
			delete _p;
			_p = NULL;
		}
	}
	T* operator->(){
		return _p->_ptr;
	}
	T& operator*(){
		return *(_p->_ptr);
	}

private:
	Asistant<T> *_p;
};
方式二:只用一個類中實現Smart_ptr(實現原理如下圖)


#pragma once
#include<iostream>
using namespace std;

//在一個類中實現智慧指標
template<class T>
class SmartPtr1{
public:
	SmartPtr1(T *ptr) :_countPtr(new int(1)), _ptr(ptr)
	{}
	~SmartPtr1(){
		if (--(*_countPtr) == 0){
			delete _ptr;
			delete _countPtr;
			_ptr = NULL;
			_countPtr = NULL;
		}
	}
	SmartPtr1(const SmartPtr1<T> &sp){
		_countPtr = sp._countPtr;
		++(*_countPtr);
		_ptr = sp._ptr;
	}
	/*
		operator=四部曲:
			1、檢查自賦值
			2、與以前“一刀兩斷”
			3、指向新世界
			4、return *this
	*/
	SmartPtr1& operator=(const SmartPtr1<T> &sp){
		if (this != &sp){
			if (--(*_countPtr) == 0){
				delete _countPtr;
				delete _ptr;
				_countPtr = NULL;
				_ptr = NULL;
			}
			_countPtr = sp._countPtr;
			++(*_countPtr);
			_ptr = sp._ptr;
		}
		return *this;
	}
	T* operator->(){
		return _ptr;
	}
	T& operator*(){
		return *_ptr;
	}
private:
	int *_countPtr;//指向引用計數的指標
	T *_ptr;       //指向實際空間的指標
};

測試程式
#include"SmartPtr.h"
#include"SmartPtr1.h"
#include<vld.h>      //用於檢測記憶體洩露

//垂懸指標:指向已被釋放空間的指標
void HangPtr()
{
	int *ptr1 = new int(10);
	int *ptr2 = ptr1;
	int *ptr3 = ptr1;

	cout << "before delete:" << endl;
	cout << *ptr1 << endl;
	cout << *ptr2 << endl;
	cout << *ptr3 << endl;

	cout << "after delete:" << endl;
	delete ptr1;
	cout << *ptr2 << endl;//所指向的空間已被釋放--->懸垂指標,程式崩潰“指日可待”
	cout << *ptr3 << endl;
}

//SmartPtr
//-------------------> SmartPtr <---------------------------
//測試拷貝建構函式
void test1(){
	int *p = new int(10);
	SmartPtr<int> sp(p);
	{
		SmartPtr<int> sp1(sp);
	}
	SmartPtr<int> sp2(sp);
}

//測試operator=
void test2()
{
	int *p = new int(10);
	SmartPtr<int> ptr(p);

	int *p1 = new int(20);
	SmartPtr<int> ptr1(p1);

	ptr1 = ptr;
	cout << *ptr << endl;
	cout << *ptr1 << endl;
}

//-------------------> SmartPtr1 <---------------------------
//測試拷貝建構函式
void test3(){
	int *p = new int(10);

	SmartPtr1<int> sp(p);
	{
		SmartPtr1<int> sp1(sp);
	}
	SmartPtr1<int> sp2(sp);
}

//測試operator=
void test4()
{
	int *p = new int(10);
	SmartPtr<int> ptr(p);

	int *p1 = new int(20);
	SmartPtr<int> ptr1(p1);

	ptr1 = ptr;
	cout << *ptr << endl;
	cout << *ptr1 << endl;
}
int main()
{
	test4();
	system("pause");
	return 0;
}