真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網站制作重慶分公司

C++string解析深淺拷貝-創(chuàng)新互聯(lián)

string類 1. 標準庫中的string類 1.1 string類(了解)
  1. 字符串是表示字符序列的類

    成都創(chuàng)新互聯(lián)長期為上千多家客戶提供的網站建設服務,團隊從業(yè)經驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網生態(tài)環(huán)境。為凌云企業(yè)提供專業(yè)的做網站、成都網站設計,凌云網站改版等技術服務。擁有10余年豐富建站經驗和眾多成功案例,為您定制開發(fā)。
  2. 標準的字符串類提供了對此類對象的支持,其接口類似于標準字符容器的接口,但添加了專門用于操作單字節(jié)字符字符串的設計特性。

  3. string類是使用char(即作為它的字符類型,使用它的默認char_traits和分配器類型(關于模板的更多信息,請參閱basic_string)。

  4. string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits和allocator作為basic_string的默認參數(shù)(根于更多的模板信息請參考basic_string)。

  5. 注意,這個類獨立于所使用的編碼來處理字節(jié):如果用來處理多字節(jié)或變長字符(如UTF-8)的序列,這個類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(jié)(而不是實際編碼的字符)來操作。

總結:

  1. string是表示字符串的字符串類

  2. 該類的接口與常規(guī)容器的接口基本相同,再添加了一些專門用來操作string的常規(guī)操作

  3. string在底層實際是:basic_string模板類的別名,typedef basic_stringstring;

  4. 不能操作多字節(jié)或者變長字符的序列。

1.2 string類的常見接口說明
函數(shù)名稱功能說明
string()構造空string類對象,即空字符串
string(const char* s)用C-string來構造string類對象
string(size_t n, char c)string類對象中包含n個字符c
string(const string& s)拷貝構造
void test()
{
    string s1;//構造空的string類對象s1
    string s2("hello yhh");//用C-string來構造string類對象
    string s3(s2);//拷貝構造s3
    string s4(8, 'a');//string類對象中含有n個字符C
}
  1. string類對象的容器操作
函數(shù)名稱共能說明
size返回字符串有效字符長度
length返回字符串有效字符長度
capacity返回空間總大小
empty檢測字符串是否為空串,是返回true,否則返回false
clear清空有效字符
reserve為字符串預留空間,不初始化
resize將有效字符的個數(shù)改成n個,多出空間用字符C填充,要初始化

注意:

  1. size()與length()方法底層實現(xiàn)原理完全相同,引入size()的原因是為了與其他容器的接口保持一
    致,一般情況下基本都是用size()。

  2. clear()只是將string中有效字符清空,不改變底層空間大小

  3. . resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數(shù)改變到n個,不同的是當字符個數(shù)增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。注意:resize在改變元素個數(shù)時,如果是將元素個數(shù)增多,可能會改變底層容量的大小,如果是將元素個數(shù)減少,底層空間總大小不變。

  4. reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數(shù),當reserve的參數(shù)小于
    string的底層空間總大小時,reserve不會改變容量大小

  5. 容量是變大不小

  6. string類對象的訪問及遍歷操作

    函數(shù)名稱功能說明
    operator[]返回pos位置的字符,const string類對象調用
    begin+endbegin獲取一個字符的迭代器 + end獲取最后一個字符下一個位置的迭 代器
    rend + rbeginbegin獲取一個字符的迭代器 + end獲取最后一個字符下一個位置的迭 代器
    范圍forC++11支持更簡潔的范圍for的新遍歷方式
  7. string類對象的修改操作

    函數(shù)名稱功能說明
    push_back在字符串后尾插字符c
    append在字符串后追加一個字符串
    operator+=在字符串后追加字符串str
    c_str返回C格式字符串
    find + npos從字符串pos位置開始往后找字符c,返回該字符在字符串中的位置(找不到返回npos)
    rfind從字符串pos位置開始往前找字符c,返回該字符在字符串中的位置
    substr在str中從pos位置開始,截取n個字符,然后將其返回

    注意:

    1. 在string尾部追加字符時,s.push_back? / s.append(1, c) / s += 'c’三種的實現(xiàn)方式差不多,一般情況下string類的+=操作用的比較多,+=操作不僅可以連接單個字符,還可以連接字符串。

    2. 對string操作時,如果能夠大概預估到放多少字符,可以先通過reserve把空間預留好

  8. string類非成員函數(shù)

    函數(shù)功能說明
    operator+盡量少用,因為傳值返回,導致深拷貝效率低
    operator>>輸入運算符重載
    operator<<輸出運算符重載
    getline獲取一行字符串
    relational operators大小比較
2. string模擬實現(xiàn)
namespace yhh
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _size + _str;
		}

		const iterator begin() const
		{
			return _str;
		}

		const iterator end() const
		{
			return _size + _str;
		}

		size_t size() const
		{
			return _size;
		}

		size_t capacity()const
		{
			return _capacity;
		}
		char* c_str() const
		{
			return _str;
		}

		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];//留給'/0'

			strcpy(_str, str);
		}//構造函數(shù),初始話列表按照聲明的順序初始話


		//傳統(tǒng)寫法
		//string(const string& s)
		//	:_str(new char[s._capacity+1])
		//	,_size(s._size)
		//	,_capacity(s._capacity)
		//{
		//	strcpy(_str, s._str);
		//}

		//string& operator=(const string& s)//賦值會把原來的值干掉
		//{
		//	if (&s != this)
		//	{
		//		//delete[] _str;
		//		//_str = new char[s._capacity + 1];//如果new失敗,就把原對象破壞了
		//		//strcpy(_str, s._str);
		//		char* tmp = new char[s._capacity + 1];
		//		strcpy(tmp, s._str);
		//		delete[] _str;
		//		_str = tmp;
		//		_size = s._size;
		//		_capacity = s._capacity;
		//	}

		//	return *this;
		//}

		//現(xiàn)代寫法
		void swap(string& tmp)
		{
			::swap(_str, tmp._str);//去全局域去找
			::swap(_size, tmp._size);
			::swap(_capacity, tmp._capacity);
		}

		string(const string& str)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(str._str);
			swap(tmp);
		}//拷貝構造

		string& operator=(const string& str)
		{
			if (this != &str)
			{
				string tmp(str._str);//tmp局部對象出了作用域調用析構函數(shù),釋放this指向的那個
				swap(tmp);
			}
			return *this;
		}// 賦值

		//string& operator=(string str)
		//{
		//	swap(str);
		//	return *this;
		//}//賦值, str就是臨時變量,自己給自己賦值都會原來的地址會變

		char& operator[](size_t pos)
		{
			assert(pos< _size);

			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos< _size);

			return _str[pos];
		}

		void reserve(size_t n)
		{
			if (n >_capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);

				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}

		void resize(size_t n, char ch = '\0')
		{
			if (n >_size)
			{
				reserve(n);
				for (size_t i = _size; i< n; i++)
				{
					_str[i] = ch;
				}
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				_str[n] = '\0';
				_size = n;
			}
		}//多了刪除數(shù)據(jù),少了就在結尾添加'\0'

		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size] = ch;//添加元素
			_size++;
			_str[_size] = '\0';//添加結尾
		}

		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len >_capacity)
			{
				reserve(_size + len);
			}//可以不要這個if,但是就會多幾次函數(shù)調用,如果不需要開辟空間的話
			//aa bb
			strcpy(_str + _size, str);//在結尾追加
			_size += len;
		}

		void append(const string& s)
		{
			append(s._str);
		}
		void append(size_t n, char ch)
		{
			reserve(_size + n);
			for (size_t i = 0; i< n; ++i)
			{
				push_back(ch);
			}
		}

		string& operator+=(const char* s)
		{
			append(s);
			return *this;
		}
		string& operator+=(const char ch)
		{
			push_back(ch);
			return *this;
		}

		string& insert(size_t pos, char ch)
		{
			assert(pos<= _size);
			if (_capacity == _size)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			size_t end = _size + 1;
			while (end >pos)
			{
				_str[end] = _str[end - 1];
				--end;
			}

			_str[pos] = ch;
			_size++;

			return *this;
		}

		string& insert(size_t pos, const char* str)
		{
			assert(pos<= _size);
			int len = strlen(str);
			if (len + _size >_capacity)
			{
				reserve(_size + len);
			}

			size_t end = _size + len;//把前一個的'/0'也拷貝走防止,在_size插入出現(xiàn)錯誤

			while (end >= pos + len)
			{
				_str[end] = _str[end - len];
				end--;
			}//因為插入了字符串就不會讓end小于0

			strncpy(_str + pos, str, len);
			_size += len;

			return *this;
		}

		string& erase(size_t pos, size_t len = npos)
		{
			assert(pos< _size);
			if (len == npos || len + pos >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}

			return *this;
		}

		void clear()
		{
			_size = 0;
			_str[0] = '\0';
		}

		size_t find(char ch, size_t pos = 0)const
		{
			assert(pos< _size);
			for (size_t i = pos; i< _size; i++)
			{
				if (ch == _str[i])
					return i;
			}

			return npos;
		}

		size_t find(const char* sub, size_t pos = 0)const//找子串
		{
			assert(sub);
			assert(pos< _size);

			// kmp/bm
			const char* ptr = strstr(_str + pos, sub);
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}
		}
		//size_t find(const char* s, size_t pos = 0) const
		//{
		//	assert(s);
		//	assert(pos< _size);
		//	const char* src = _str + pos;

		//	while (*src)
		//	{
		//		const char* tmp = src;
		//		const char* match = s;
		//		while (*match == *tmp && *match && *tmp)
		//		{
		//			match++;
		//			tmp++;
		//		}
		//		if (*match == '\0')
		//		{
		//			return src - _str;
		//		}
		//		else
		//		{
		//			src++;
		//		}
		//	}

		//	return npos;
		//}
		string substr(size_t pos, size_t len = npos) const
		{
			assert(pos< _size);
			size_t realLen = len;
			if (len == npos || pos + len >_size)
			{
				realLen = _size - pos;
			}

			string sub;
			for (size_t i = 0; i< realLen; ++i)
			{
				sub += _str[pos + i];
			}

			return sub;
		}//獲得_str中的字串,而且是新開辟的空間

		bool operator<(const string& s)const
		{
			return strcmp(_str, s._str)< 0;
		}
		bool operator>(const string& s)const
		{
			return !(*this<= s);
		}
		bool operator>=(const string& s)const
		{
			return !(*this< s);
		}
		bool operator<=(const string& s)const
		{
			return *this< s || *this == s;
		}
		bool operator==(const string& s)const
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator!=(const string& s)const
		{
			return !(*this == s);
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}//析構函數(shù)

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	public:
		static size_t npos;/
	};

	size_t string::npos = -1;

	ostream& operator<<(ostream& out, const string& s)
	{
		for (size_t i = 0; i< s.size(); i++)
		{
			cout<< s[i];
		}

		return out;
	}

	//istream& operator>>(istream& in,  string& s)
	//{
	//	s.clear();
	//	char ch;
	//	ch = in.get();

	//	while (ch != ' ' && ch != '\n')
	//	{
	//		size_t old = s.capacity();
	//		s += ch;
	//		if (s.capacity() != old)
	//		{
	//			cout<< old<< "擴容"<< s.capacity()<< endl;
	//		}
	//		ch = in.get();
	//	}

	//	return in;
	//}
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char ch;
		ch = in.get();

		const size_t N = 32;
		char buff[N];
		size_t i = 0;

		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}//類似于緩存器這樣的

		buff[i] = '\0';
		s += buff;
		return in;
	}
}
3. 深淺拷貝 3.1 淺拷貝

淺拷貝:也稱位拷貝,編譯器只是將對象中的值拷貝過來。如果對象中管理資源,最后就會導致多個對象共享同一份資源,當一個對象銷毀時就會將該資源釋放掉,而此時另一些對象不知道該資源已經被釋放,以為還有效,所以當繼續(xù)對資源進項操作時,就會發(fā)生發(fā)生了訪問違規(guī) 。

在這里插入圖片描述

說明:上述String類沒有顯式定義其拷貝構造函數(shù)與賦值運算符重載,此時編譯器會合成默認的,當用s1構造s2時,編譯器會調用默認的拷貝構造。最終導致的問題是,s1、s2共用同一塊內存空間,在釋放時同一塊空間被釋放多次而引起程序崩潰,這種拷貝方式,稱為淺拷貝。

3.2 深拷貝

每個對象都有一份獨立的資源,不要和其他對象共享。

如果一個類中涉及到資源的管理,其拷貝構造函數(shù)、賦值運算符重載以及析構函數(shù)必須要顯式給出。一般情
況都是按照深拷貝方式提供。

在這里插入圖片描述

4.寫實拷貝

寫時拷貝就是一種拖延癥,是在淺拷貝的基礎之上增加了引用計數(shù)的方式來實現(xiàn)的。
引用計數(shù):用來記錄資源使用者的個數(shù)。在構造時,將資源的計數(shù)給成1,每增加一個對象使用該資源,就給
計數(shù)增加1,當某個對象被銷毀時,先給該計數(shù)減1,然后再檢查是否需要釋放資源,如果計數(shù)為1,說明該
對象時資源的最后一個使用者,將該資源釋放;否則就不能釋放,因為還有其他對象在使用該資源

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧


新聞標題:C++string解析深淺拷貝-創(chuàng)新互聯(lián)
分享路徑:http://weahome.cn/article/ceoghs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部