C++ String的實現

String的實現需要注意的是String的拷貝構造。它的拷貝構造有深拷貝和淺拷貝之分。

我們先來用淺拷貝實現String

class String
{
public:
	String()
	{
		str = new char('A');
	}
	String(char *s)
	{
		str = new char[strlen(s) + 1];
		if (str != NULL)
		{
			strcpy(str, s);
		}
	}
	String(const String& s)
	{
		str=s.str;
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
		      str=s.str;
		}
		return *this;
	}

private:
	char *str;
};

void test()
{
	String s1("hello world");
	String s2(s1);
}

當s1,s2出自的作用域時,會自動調用析構函數,此時s1,s2指向同一片內存。所以這塊內存會被釋放兩次,程序會崩潰。

wKiom1cE006h6wLEAAAgqxHOc44715.png


所以在這裏我們要採用深拷貝的方式


構造函數和賦值運算符重載

String(const String& s)
	{
		str = new char[strlen(s.str) + 1];    //new出來一塊新的空間
		if (str)
		{
			strcpy(str, s.str);
		}
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			if (str != NULL)
			{
				delete[] str;
				str = new char[strlen(s.str) + 1];
				strcpy(str, s.str);
			}
		}
		return *this;
	}

wKioL1cE1Tbx3ARFAACNVhiAVJc549.png

還有一種方法可以解決這個一塊空間會被多次釋放的問題,那就是寫時拷貝

在第一次構造一個對象的時候,多開闢四個字節當做計數器,用來記錄有幾個指針指向這塊空間。每當用這塊空間拷貝構造一個新對象或者把這塊空間賦給另外一個對象時,計數器相應增加。那麼當調用析構函數時,每次計數器減一,當計數器減到一時,說明只有一個指針指向這塊空間,此時再把這塊空間delete,就不會出現一塊空間多次釋放的問題了。

class String
{
public:
	String(char *str="")
		:_str(new char[strlen(str)+1+4])
	{
		*((int *)_str) = 1;         //將開闢的空間前4個字節強制轉換成整型並賦爲1
		_str = _str + 4;       //將_str重新定爲真正字符串開始的地方,這樣比較方便
		strcpy(_str, str);     //不用每次向後找
	}
	String(const String& str)
	{
		_str = str._str;
		(*((int *)(_str - 4)))++;    
	}
	~String()
	{
		if (*_str != NULL)    
		{
			if (((*((int *)(_str - 4)))--) == 0)    //判斷計數器是否減到0
			{
				delete[] (_str-4);
			}
		}
	}
public:
	String& operator=(const String& str)
	{
		if (this != &str)
		{
			if (((*((int *)(_str - 4)))--) == 0)
			{
				delete[] (_str-4);
			}
			_str = str._str;
			(*(int *)(str._str - 4))++;
			return *this;
		}
	}
	char& operator[](int index)
	{
		char *tmp = _str;
		if (((*(int *)(_str - 4))-1) != 0)
		{
			(*(int *)(_str - 4))--;
			_str = new char[strlen(_str) + 5];
			(*(int *)(_str + 4)) = 1;
			_str = _str - 4;
			strcpy(_str, tmp);
		}
		return _str[index];
	}
private:
	char *_str;
};

wKiom1cE2V2jqZHuAAAoTAB_f3c973.png

但是這樣做也有一個壞處。就是指向同一塊空間的指針,只要改一個指針指向的內容,等於其他的指針指向的內容也跟着改變了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章