亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++?STL之string的模擬實現(xiàn)實例代碼

 更新時間:2023年01月05日 09:30:20   作者:李奇同學(xué)喵喵嗚~  
C++中有命名空間的存在,我們只需把我們的代碼封到自定義的命名空間即可,下面這篇文章主要給大家介紹了關(guān)于C++?STL之string的模擬實現(xiàn)的相關(guān)資料,需要的朋友可以參考下

前言

上一章我們對string的常見接口及使用進(jìn)行了講解,接下來我們將對一些常見的接口,包括構(gòu)造函數(shù),析構(gòu)函數(shù),運算符重載等等進(jìn)行模擬實現(xiàn).方便我們理解string接口實現(xiàn)的原理.

在講解之前先說一下string的成員變量.

首先是字符串內(nèi)容_str,再是字符串的大小_size,最后是字符串的總?cè)萘看笮?strong>_capacity.

class string
	{
	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};

構(gòu)造函數(shù)

缺省值是一個空串,再給_str開辟空間時要多開辟一個空間存儲'\0'

開好了空間最后需要把內(nèi)容拷貝到_str.

		string(const char* str = "")
		{
			//這里有個細(xì)節(jié),就是先計算出_size大小,然后再直接把_size賦值給_capacity,省了一次strlen()的調(diào)用.
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

析構(gòu)函數(shù)

完成對string類成員的資源清理,空間釋放等一些操作.

        ~string()
		{
            //釋放_str的空間,并將其指向的空間置為空
			delete[] _str;
			_str = nullptr;
 
			_size = _capacity = 0;
		}

拷貝構(gòu)造函數(shù)

說到string的拷貝構(gòu)造函數(shù),這里一定會涉及到深淺拷貝問題.

所以在講解它的拷貝構(gòu)造函數(shù)之前必須先了解它

淺拷貝:也稱位拷貝,編譯器只是將對象中的值拷貝過來。如果對象中管理資源,可能就會導(dǎo)致多個對象共享同一份資源,當(dāng)一個對象銷毀時就會將該資源釋放掉,但是其他的對象不知道該資源已經(jīng)被釋放了,以為資源還有效,所以他們會繼續(xù)對這個資源進(jìn)行訪問。這時就出現(xiàn)了違法訪問。深拷貝就是為了解決淺拷貝的問題。

深拷貝:就是給自己重新開辟一塊空間,并將數(shù)據(jù)拷貝到新開辟的空間中,如果一個類中涉及到資源的管理,其拷貝的構(gòu)造函數(shù),賦值運算符重載以及析構(gòu)函數(shù)必須要顯式給出。(就是要手動寫,不能用編譯器自動生成的)。一般這種情況都是按照深拷貝方式提供。

所以拷貝的時候,需要重新給_str開辟一塊空間.

		string(const string& s)
			:_str(new char[s._capacity + 1])
			, _size(s._size)
			, _capacity(s._capacity)
		{
			strcpy(_str, s._str);
		}

這里也用圖淺淺的介紹一下淺拷貝和深拷貝的區(qū)別.

operator=賦值運算符重載

正如上一個所說,=賦值運算符也同樣存在深淺拷貝的問題,所以也必須進(jìn)行深拷貝.

它和拷貝構(gòu)造的主要區(qū)別就是:拷貝構(gòu)造是對象還沒有初始化時進(jìn)行拷貝,而賦值運算符重載是對一個已經(jīng)存在的變量進(jìn)行賦值.

當(dāng)然同樣這里也需要深拷貝

也有一些需要注意的問題:例如s1=s2.我們把s2賦值給s1后,那么原本的s1空間該怎么辦呢?

我們的解決方案是:

把原本的s1空間釋放掉,然后再開辟一塊和s2大小相同的空間,再把內(nèi)容從s2拷貝到s1

		//= 運算符重載
		string& operator=(const string& s)
		{
			//不能自己賦值給自己
			if (this != &s)
			{//先釋放掉原本的空間
				delete[] _str;
				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

c_str

c_str就是返回c語言風(fēng)格的字符串,既返回char*類型字符串,返回字符串首地址即可.

	const char* c_str() const
	{
		return _str;
	}

為什么加const呢?

第一個const是為了使普通對象和const對象都可以調(diào)用這個函數(shù),因為權(quán)限只可以縮小,不可以放大.

第二個const是保證函數(shù)體內(nèi)的內(nèi)容不會被改變,既this指針指向的內(nèi)容無法被改變.

operator[]

實現(xiàn)[]重載,是指傳過來一個下標(biāo)index,返回它index下標(biāo)所對應(yīng)的值

目的是讓字符串可以像數(shù)組一樣訪問每一個元素.

		char& operator[](size_t index)
		{
            //下標(biāo)必須小于字符串總大小
			assert(index < _size);
 
			return _str[index];
 
		}

當(dāng)然為了const對象也可以調(diào)用,我們可以再寫一個const修飾的operator[].

		const char& operator[](size_t index) const
		{
			assert(index < _size);
 
			return _str[index];
		}

size()

寫一個函數(shù),直接返回_size即可

        size_t size() const
		{
			return _size;
		}

那可能會有人想問了:既然返回_size,那我們直接調(diào)用它這個成員不就行了,為什么還有套一層函數(shù)呢?

這是因為_size是被private修飾的,我們是不能直接訪問私有成員的.

所以需要實現(xiàn)一個公有的函數(shù)間接訪問_size.

capacity()

這個所注意的和size完全一致.

		size_t capacity() const
		{
			return _capacity;
		}

empty()

只需要判斷當(dāng)前的size是否等于0即可.

		bool empty() const
		{
			return _size == 0;
		}

operator+=

這個重載運算符我們上一章講過是可以插入字符或者插入字符串的,這里也分別復(fù)用了push_back和append(),這兩個函數(shù)后面將模擬實現(xiàn).

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

擴(kuò)容函數(shù)(reserve)

調(diào)整容量大小到n

先new一個n+1的新空間,再把原來的數(shù)據(jù)拷貝到新空間中去,然后釋放掉原來的空間,然后將capacity設(shè)置為n.

void reserve(size_t n)
		{
			//n應(yīng)該大于之前的容量
			if (n > _capacity)
			{
				//先開辟大小為n+1的空間
				char* tmp = new char[n + 1];
				//將原來的數(shù)據(jù)拷貝到tmp
				strcpy(tmp, _str);
				//釋放掉原來的數(shù)據(jù)
				delete[] _str;
				
				//將擴(kuò)容后的數(shù)據(jù)重新賦給_str
				_str = tmp;
				_capacity = n;
			}
		}

畫圖來理解一下它 

resize()

resize會有以下兩種情況:

1.若n < _size,既重新調(diào)整后的大小小于原來的大小,會發(fā)生數(shù)據(jù)截斷,只保留前n個字符.

2.若n > _size,這里直接復(fù)用reserve即可

既如果n<_capacity,此時_capacity不發(fā)生變化,多出的空間用ch替代.

如果n>_capacity,此時_capacity需要擴(kuò)容(1.5倍速度,不一定是n),直到最接近為止.

		void resize(size_t n, char ch = '\0')
		{
			if (n > _size)
			{
				//插入數(shù)據(jù)
                //reserve會和容量進(jìn)行比較以及是否需要闊人
				reserve(n);
                //多余的字符用ch替代    
				for (size_t i = _size; i < n; i++)
				{
					_str[i] = ch;
				}
                //字符串結(jié)束
				_str[n] = '\0';
				_size = n;
			}
			else
			{
				//刪除數(shù)據(jù)
                 //直接將第n個數(shù)據(jù)改為'\0',這樣相當(dāng)于將后面的數(shù)據(jù)全部刪除了.
				_str[n] = '\0';
				_size = n;
			}
		}

push_back()

push_back的作用是在原字符串后上拼接一個字符,首先我們現(xiàn)需要判斷空間是否足夠,如不夠,則需要擴(kuò)容,復(fù)用之前的reserve函數(shù),再進(jìn)行插入數(shù)據(jù),最后加上'\0'.

當(dāng)然還可以利用復(fù)用insert()函數(shù)進(jìn)行插入,這個后面再實現(xiàn).

		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
				_str[_size] = ch;
				++_size;
				_str[_size] = '/0';
			}
		}

還以復(fù)用insert這樣插入,會使代碼健壯性更強,更加簡潔.

這個inser()函數(shù)后面會實現(xiàn).

			insert(_size, ch);

append()

這個與push_back不同的是:push_back()只能插入一個字符,append()只可以插入一個字符串.

這里的問題就出現(xiàn)了,我們不知道追加的字符串長度,自然擴(kuò)容的時候也不知道擴(kuò)大到多少,是2倍還是3倍,所以這里要看插入的字符串的長度len,只要要讓空間開到_size+len.

讓空間滿足最低的情況,能把所有的字符容納下,最后利用strcpy將其數(shù)據(jù)拷貝過來即可.

        	void append(const char* str)
		    {
				size_t len = strlen(str);
				if (_size + len > _capacity)
				{
					reserve(_size + len);
				}
				strcpy(_str + _size, str);
				_size = _size + len;
			}

當(dāng)然同樣可以復(fù)用insert函數(shù).

    insert(_size, str);

下面就該說insert函數(shù)了.

insert()

insert也分為兩種情況:插入一個字符或插入多個字符(字符串)

插入一個字符:方法類似于順序表的插入

		string& insert(size_t pos, char ch)
		{
            //插入的位置必須要與字符串大小
			assert(pos <= _size);
            //如果空間滿了,則需要擴(kuò)容
			if (_size == _capacity)
			{
				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);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
            //先把空間騰出來
			size_t end = _size + len;
			while (end >= pos + len)
			{
				_str[end] = _str[end - len];
				--end;
			}
            //再把利用strncpy把指定長度的字符串插入
			strncpy(_str + pos, str, len);
			_size = _size + len;
 
		}

說了插入就該說刪除了.

erase()

這個函數(shù)也比較巧妙,首先輸入兩個參數(shù):第一個參數(shù)是要開始刪除的下標(biāo),第二個參數(shù)是要刪除的長度.

首先第二個參數(shù)默認(rèn)缺省值是npos,npos是一個非常大的數(shù).

首先判斷l(xiāng)en是否等于npos或者當(dāng)前位置+len是否大于總長度,若是,則直接將pos位置置為'\0',后面的元素也就相當(dāng)于刪除了

如果不是,則把pos+len之后的元素拷貝到pos位置之后,這樣就相當(dāng)于刪除了pos~pos+len之間的這一段字符.再把_size-len,相當(dāng)于是一個覆蓋的過程.

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

find()

也是實現(xiàn)兩個,利用strstr()函數(shù)來查找字符串.

1.如果查找一個字符

  如果找到,則直接返回字符所對應(yīng)的下標(biāo)pos,否則返回npos.

2.如果查找一個字符串

   對于這種情況,找到字符串后,我們需要返回第一個字符的下標(biāo),通過指針差值確定目標(biāo)字符串的位置。

1.查找一個字符

思路很簡單,就是利用循環(huán)

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

2.查找一個字符串

利用strstr函數(shù),從第pos個位置開始查找,如果找到則返回目標(biāo)字符串的首元素地址,若沒有找到則返回空指針

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

substr()

 這個函數(shù)實現(xiàn)比較簡單,復(fù)用之前實現(xiàn)的+=即可

首先計算出實際要切割的長度realLen = len

如果pos+len>_size或者len == npos,則需要重新計算realLen = _size - pos

然后循環(huán)realLen次,創(chuàng)建一個string類型的sub變量,每次利用sub+=這個字符即可.

 
		string substr(size_t pos, size_t len = npos)
		{
			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;
		}

比較大小函數(shù)

實現(xiàn)比較大小,只需要實現(xiàn)兩個運算符重載即可:

1. > 或 <其中任意一個

2.==

剩下的>=、<=、!=等等復(fù)用即可.

實現(xiàn)> 或 < 時,利用strcmp比較函數(shù)即可.

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

 這樣string的模擬實現(xiàn)基本就完成了,下面是總代碼:

namespace hmylq
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
 
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
		//拷貝構(gòu)造 - - - 1
		string(const string& s)
			:_str(new char[s._capacity + 1])
			, _size(s._size)
			, _capacity(s._capacity)
		{
			strcpy(_str, s._str);
		}
		//拷貝構(gòu)造 - - - 2
	/*	string(const string& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(_str, tmp._str);
			swap(_size, tmp._size);
			swap(_capacity, tmp._capacity);
		}*/
 
		//析構(gòu)函數(shù)
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		
		iterator begin()
		{
			return _str;
		}
 
		iterator end()
		{
			return _str + _size;
		}
 
		const_iterator begin() const
		{
			return _str;
		}
 
		const_iterator end() const
		{
			return _str + _size;
		}
 
		/
		void push_back(char ch)
		{
			/*if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
				_str[_size] = ch;
				++_size;
				_str[_size] = '/0';
			}*/
			insert(_size, ch);
		}
 
	
		string& operator += (char ch)
		{
			push_back(ch);
 
			return *this;
		}
 
		void append(const char* str)
		{
			/*size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			strcpy(_str + _size, str);
			_size = _size + len;*/
			insert(_size, str);
		}
 
		string& operator += (const char* str)
		{
			append(str);
 
			return *this;
		}
 
 
 
		//= 運算符重載
		string& operator=(const string& s)
		{
			if (this != &s)
			{
				delete[] _str;
				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);
				_size = s._size;
				_capacity = s._capacity;
				return *this;
			}
		}
 
 
	
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
 
		void swap(string& tmp)
		{
			::swap(_str, tmp._str);
			::swap(_size, tmp._size);
			::swap(_capacity, tmp._capacity);
		}
 
		const char* c_str() const
		{
			return _str;
		}
		//
		size_t size() const
		{
			return _size;
		}
 
		size_t capacity() const
		{
			return _capacity;
		}
		
		bool empty() const
		{
			return _size == 0;
		}
 
		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;
			}
		}
 
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
 
				_str = tmp;
				_capacity = n;
			}
		}
		
		/
		char& operator[](size_t index)
		{
			assert(index < _size);
 
			return _str[index];
 
		}
 
		const char& operator[](size_t index) const
		{
			assert(index < _size);
 
			return _str[index];
		}
 
		//
 
		bool operator >(const string& s) const
		{
			return strcmp(_str, s._str) > 0;
		}
 
		bool operator ==(const string& s) const
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator >= (const string& s) const
		{
			return *this > s || *this == s;
		}
		bool operator <(const string& s) const
		{
			return !(*this >= s);
		}
		bool operator <=(const string& s) const
		{
			return !(*this > s);
		}
		bool operator !=(const string& s)
		{
			return !(*this == s);
		}
 
		
 
		size_t find(char ch, size_t pos = 0)
		{
			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)
		{
			assert(sub);
			assert(pos < _size);
 
			const char* ptr = strstr(_str + pos, sub);
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}
		}
 
		string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				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);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			size_t end = _size + len;
			while (end >= pos + len)
			{
				_str[end] = _str[end - len];
				--end;
			}
			strncpy(_str + pos, str, len);
			_size = _size + len;
 
		}
 
		void erase(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
		}
 
	
 
 
		string substr(size_t pos, size_t len = npos)
		{
			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;
		}
 
 
	private:
		char* _str;
		int _size;
		int _capacity;
		const static size_t npos = -1;
	};
}

總結(jié)

到此這篇關(guān)于C++ STL之string的模擬實現(xiàn)的文章就介紹到這了,更多相關(guān)C++ STL string模擬實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實現(xiàn)合并字符串

    C語言實現(xiàn)合并字符串

    今天小編就為大家分享一篇C語言實現(xiàn)合并字符串,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • C++實現(xiàn)本地TCP通訊的示例代碼

    C++實現(xiàn)本地TCP通訊的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C++如何利用TCP技術(shù),實現(xiàn)本地ROS1和ROS2的通訊,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • vector與map的erase()函數(shù)詳細(xì)解析

    vector與map的erase()函數(shù)詳細(xì)解析

    vector和map都不能將it++寫在for循環(huán)中,而在循環(huán)體內(nèi)erase(it)
    2013-09-09
  • C++實現(xiàn)指針空值的示例代碼

    C++實現(xiàn)指針空值的示例代碼

    本文主要介紹了C++實現(xiàn)指針空值的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Qt中控件的函數(shù)使用教程分享

    Qt中控件的函數(shù)使用教程分享

    這篇文章主要為大家詳細(xì)介紹了Qt中部分控件(Text Edit編輯框、Combo Box下拉框、List Wiget和Label)函數(shù)的使用,感興趣的小伙伴可以了解一下
    2022-12-12
  • 關(guān)于C++中push_back()函數(shù)的用法及代碼實例

    關(guān)于C++中push_back()函數(shù)的用法及代碼實例

    push_back是vector的一個方法,表示將一個元素存儲到容器的末尾,下面這篇文章主要給大家介紹了關(guān)于C++中push_back()函數(shù)用法的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • vs運行時報C4996代碼錯誤的問題解決

    vs運行時報C4996代碼錯誤的問題解決

    C4996錯誤的意思:是VS覺得strcpy這函數(shù)不安全,建議你使更安全的函數(shù),那么如何解決呢,本文主要介紹了vs運行時報C4996代碼錯誤的問題解決,感興趣的可以了解一下
    2024-01-01
  • C++ 中約瑟夫環(huán)替換計數(shù)器m(數(shù)組解決)

    C++ 中約瑟夫環(huán)替換計數(shù)器m(數(shù)組解決)

    這篇文章主要介紹了C++ 中約瑟夫環(huán)替換計數(shù)器m(數(shù)組解決)的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 總結(jié)了24個C++的大坑,你能躲過幾個

    總結(jié)了24個C++的大坑,你能躲過幾個

    這篇文章主要介紹了總結(jié)了24個C++的大坑,你能躲過幾個,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-05-05
  • Qt自定義控件實現(xiàn)簡易儀表盤

    Qt自定義控件實現(xiàn)簡易儀表盤

    這篇文章主要為大家詳細(xì)介紹了Qt自定義控件實現(xiàn)簡易儀表盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12

最新評論