1. 程式人生 > 其它 >C++(12):String型別

C++(12):String型別

一、普通String型別

#include<assert.h>
//string型別
class String
{
	char* str;  //new  FILE *fp   thread(要重寫拷貝和賦值,防止出現淺拷貝和淺賦值)
	String(char* s, int)
	{
		str = s;
	}
public:
	String(const char* s = nullptr) 
	{
		if (s != nullptr)
		{
			int len = strlen(s) + 1;
			str = new char[len];
			strcpy_s(str, len, s); //len是str開闢的空間長度
		}
		else
		{
			str = new char[1]; //僅指向一個位元組
			this->str[0] = '\0'; //一定讓他不為空,指向指向'\0'的一個空串
			//否則賦值,拷貝等,都要考慮四種情況,誰為不為空
			//eg:s1 NULL s2 "defe"
			//this->str = '\0';是將其置為空指標 
		}
	}
	~String()
	{
		if (str != nullptr)
		{
			delete[] str;
		}
		str = nullptr;
	}
	String(const String& s) //淺拷貝
	{
		//str = s.str; //共享資源,共享記憶體空間,會有重複釋放的問題
		if (s.str != nullptr) //深拷貝
		{
			int len = strlen(s.str) + 1;
			str = new char[len];
			strcpy_s(str, len, s.str); //len是str開闢的空間長度
		}
	}
	String& operator = (const String& s) 
	{
		if (this!= &s)
		{
			//str = s.str;  //淺賦值
			delete[] str;  //深賦值
			int len = strlen(s.str) + 1;
			str = new char[len];
			strcpy_s(str, len, s.str);
		}
		return *this;
	}

	//移動構造:是資源的移動(減輕對堆區不斷開闢釋放的過程)
	String(String&& s)
	{
		str = s.str;
		s.str = nullptr;
	}
	//移動賦值
	String& operator=(String&& s)
	{
		if (this != &s)
		{
			delete[] str;
			str = s.str;
			s.str = nullptr;
		}
		return *this;
	}
	String operator+(const String& s) const
	{
		int total = strlen(this->str) + strlen(s.str) + 1;
		char* sp = new char[total];
		strcpy_s(sp, total, this->str);
		strcat_s(sp, total, s.str);

		//return String(sp) //調動構造產生一個臨時物件,sp指向的空間就沒有釋放掉
		return String(sp, 1); //構建的臨時物件的str將指向sp,將此物件賦給s3,資源移動
	} //物件+物件

	String operator+(const char* s) const //物件+變數
	{
		return *this + String(s);
	}
	String& operator+=(const String& s)
	{
		char* tmp = this->str;
		int total = strlen(tmp) + strlen(s.str) + 1;
		str = new char[total];
		strcpy_s(str, total, tmp);
		strcat_s(str, total, s.str);
		delete[] tmp; //tmp是原來str指向的資源
		return *this;
	} //s1 += s2
	String& operator+=(const char* s) //物件+=變數
	{
		return *this += String(s);
	}
	char& operator[] (const int index) const
	{
		assert(index >= 0 && index < strlen(this->str));
		return str[index];
	}
	const char& operator[] (const int index) const
	{
		assert(index >= 0 && index < strlen(this->str));
		return str[index];
	}
	ostream& operator<<(ostream& out) const
	{
		out << str;
		return out;
	} //s1<<cout; s1.operator<<(cout);operator<<(&s1,cout)
};

//設為全域性函式,放入類中作為成員函式,引數列表省略了this指標,將變為3個引數
String operator+(const char* s, const String& st) //變數+物件
{
	return String(s) + st;  
}

String fun()
{
	String tmp("nswubd");
	return tmp;
}
ostream& operator<<(ostream& out, const String& s)
{
	s << cout;
	return cout;
}

int main()
{
	//String s1("wejbfwue");
	//String s2("dneide");
	//String s3(s1);

	String s1 = fun(); //構建的臨時物件就是s1,移動賦值

	String s2("tulun"); 
	s2 = fun(); //深拷貝,tmp賦給臨時物件,析構掉tmp,把臨時物件賦給s2,把臨時物件的資源給s2

	String s1("dheudh");
	s1 = std::move(s2); //當沒寫賦值語句時,預設的移動賦值(不好用,要重寫):是將字串拷貝到s1所指向的空間,不會刪除s2的資源,將內容直接拷貝
	
	String s4("wbfuwf");
	String s5("ejiwdewdw");
	s4 = s5; //呼叫普通的賦值語句,因為s5有名字,不能進行右值引用
	
	String s6; //s6中放的是‘\0’
	s6 = s4 + s5;

	s4 += s5;

	cout << s1 << endl; //輸出

	return 0;
}

寫賦值函式時都要考慮四種情況:
not not
not nullptr
nullptr not
nullptr nullptr
二、字元陣列為柔性陣列的String

class String
{
	//柔性陣列
	struct StrNode
	{
		int len; //字串的長度
		int size; //字串的空間大小
		int ref; //引用計數
		char data[]; //柔性陣列, 定義在最後
	};
private:
	StrNode* str;
	String(StrNode* s)
	{
		str = s;
	}
public:
	String(const char* s = nullptr): str(nullptr)
	{
		if (s != nullptr)
		{
			int len = strlen(s) + 1;
			str = (StrNode*)malloc(sizeof(StrNode) + 2 * len);  
			if (str == nullptr) exit(EXIT_FAILURE);
			str->len = len;
			str->size = 2 * len;
			str->ref = 1;
			strcpy_s(str->data, 2 * len, s);
		}
	}
	~String()
	{
		if (str != nullptr && -- this->str->ref == 0)
		{
			free(this->str);
		}
		str = nullptr;
	}
	String(const String& s) :str(s.str)
	{
		if (str != nullptr)
		{
			str->ref += 1;
		}
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			if (str != nullptr && --str->ref == 0)
			{
				free(str);
			}
			str = s.str;
			if(str != nullptr)
			{
				str->ref += 1;
			}
		}
		return *this;
	} //s1 =s2(四種情況)

	//移動
	String(String&& s)
	{
		if (str != nullptr && --str->ref == 0)
		{
			free(str);
		}
		str = s.str;
		s.str = nullptr;
	}
	String& operator=(String&& s)
	{
		if (this != &s)
		{
			if (str != nullptr && --str->ref == 0)
			{
				free(str);
			}
			str = s.str;
			s.str = nullptr;
		}
		return *this;
	}
	String operator+(const String& s) const
	{
		//先開size
		int total = 1;
		if (str != nullptr) total += str->len;
		if (s.str != nullptr) total += s.str->len;
		StrNode* sp = (StrNode*)malloc(sizeof(StrNode) + 2 * total);
		
		if (sp == nullptr) exit(EXIT_FAILURE);
		if (str != nullptr) strcpy_s(sp->data, 2 * total, str->data);
		if (s.str != nullptr) strcat_s(sp->data, 2 * total, s.str->data);

		//設定StrNode的變數的值
		sp->len = total - 1;
		sp->size = 2 * total;
		str->ref = 1;
		return String(sp);
	} //四種情況

};
int main()
{
	String s1("iewbd");
	String s2("iewbciwebc");
	String s3;
	String s4(s1);
	String s5(s2);
	s3 = s1 + s2;
	//s3 = s1 + "neonwoi";
	//s3 = "oenw" + s1;
	s1 += s2;
	//s1 += "iedi";
	return;
}