【ONE·C++||vector(二)】-創(chuàng)新互聯(lián)

總言

??主要講述vector的模擬實(shí)現(xiàn)。

創(chuàng)新互聯(lián)專注于木蘭網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供木蘭營(yíng)銷型網(wǎng)站建設(shè),木蘭網(wǎng)站制作、木蘭網(wǎng)頁(yè)設(shè)計(jì)、木蘭網(wǎng)站官網(wǎng)定制、微信小程序服務(wù),打造木蘭網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供木蘭網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。文章目錄
  • 總言
  • 1、基本框架搭建:成員變量
  • 2、對(duì)構(gòu)造函數(shù)、析構(gòu)函數(shù)
  • 3、增刪查改、空間擴(kuò)容
    • 3.1、vector::push_back、vector::pop_back
    • 3.2、vector::reserve、vector::capacity、vector::size
    • 3.3、operator[ ]
    • 3.4、遍歷:迭代器(begin、end)、范圍for
    • 3.5、vector::insert、vector::erase 迭代器失效
      • 3.5.1、vector::insert
      • 3.5.2、迭代器失效
      • 3.5.3、vector::erase
      • 3.5.5、細(xì)節(jié)問(wèn)題:不同編譯器下的迭代器失效
    • 3.6、vector::resize
    • 3.7、vector::front、vector::back
  • 4、拷貝構(gòu)造與賦值:vector的深拷貝問(wèn)題
    • 4.1、深淺拷貝說(shuō)明
    • 4.2、vector拷貝構(gòu)造演示
      • 4.2.1、寫(xiě)法一:自己開(kāi)辟空間,自己拷貝數(shù)據(jù)
      • 4.2.2、寫(xiě)法二:復(fù)用
      • 4.2.3、使用迭代器區(qū)間構(gòu)造構(gòu)造函數(shù)
      • 4.2.4、寫(xiě)法三:復(fù)用4.2.3、vector:: swap
      • 4.2.5、構(gòu)造函數(shù):n個(gè)val值
    • 4.3、vector賦值:operator=
    • 4.4、二維數(shù)組下深淺拷貝問(wèn)題

??

1、基本框架搭建:成員變量

??同string類模擬實(shí)現(xiàn)一致,此處為了解決命名沖突問(wèn)題,我們使用添加命名空間myvector的方式來(lái)處理。

#pragma once
namespace myvector
{templateclass vector
	{typedef T* iterator;//將模板T*命名為迭代器iterator
	public:

	private:
		iterator _start;//起始
		iterator _finish;//結(jié)束
		iterator _end_of_storage;//容量空間
	};
}

??由于后續(xù)涉及到迭代器問(wèn)題,若將typedef T* iterator;定義成私有,則無(wú)法在類外很好的使用。此處修改如下:

#pragma once
namespace myvector
{templateclass vector
	{	public:
		typedef T* iterator;//將模板T*命名為迭代器iterator
		typedef const T* const_iterator;
	private:
		iterator _start;//起始
		iterator _finish;//結(jié)束
		iterator _end_of_storage;//容量空間
	};
}

??
??

2、對(duì)構(gòu)造函數(shù)、析構(gòu)函數(shù)

??1)、構(gòu)造函數(shù)
??對(duì)構(gòu)造函數(shù),我們之前學(xué)習(xí)時(shí)看到其中有內(nèi)存池的相關(guān)內(nèi)容,此處由于我們暫時(shí)沒(méi)學(xué)習(xí)它,故對(duì)vector的模擬實(shí)現(xiàn)中我們不使用它。

vector() //構(gòu)造函數(shù)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

??
??2)、析構(gòu)函數(shù)

~vector()//析構(gòu)函數(shù)
		{	delete[] _start;//null出來(lái)的空間是連續(xù)一塊的,以_start為起始點(diǎn)。注意delete的使用方式
			_start = _finish = _end_of_storage = nullptr;
		}

??
??

3、增刪查改、空間擴(kuò)容 3.1、vector::push_back、vector::pop_back

??1)、庫(kù)函數(shù)中聲明回顧

??2)、push_back模擬實(shí)現(xiàn)

void push_back(const T& x)
		{	//涉及擴(kuò)容檢查
			if (_finish == _end_of_storage)
			{		reserve(capacity() == 0?4:capacity() * 2);
			}
			//尾插數(shù)據(jù)
			*_finish = x;
			_finish++;

		}

??為什么需要使用引用和const修飾?
??因?yàn)檫@里使用的是T模板參數(shù),我們傳入的值可能是內(nèi)置類型,也可能是自定義類型,如果是后者,則傳值傳參代價(jià)很大。
??
??3)、pop_back模擬實(shí)現(xiàn)

void pop_back()
		{	assert(_finish >_start);
			_finish--;
		}

??
??
??
??

3.2、vector::reserve、vector::capacity、vector::size

??1)、庫(kù)函數(shù)中聲明回顧

在這里插入圖片描述

??2)、模擬實(shí)現(xiàn)

size_t size()const
		{	return _finish - _start;
		}


		size_t capacity()const
		{	return _end_of_storage - _start;
		}
void reserve(size_t n)
		{	if (n >capacity())//滿足該條件才進(jìn)行擴(kuò)容
			{		size_t sz = size();//因?yàn)楹罄m(xù)重新確定指向關(guān)系時(shí)需要知道size值
				T* tmp = new T[n];
				if (_start)//說(shuō)明原先空間有數(shù)據(jù),
				{memcpy(tmp, _start, sizeof(T) * sz);//需要挪動(dòng)
					delete[] _start;//釋放舊空間
				}
				//重新確定指向關(guān)系
				_start = tmp;
				_finish = _start + sz;
				//_finish = _start + size();//如果是在這里獲取size值,則在原先空間有數(shù)據(jù)的情況下,_start已經(jīng)被delete

				_end_of_storage = _start + n;
			}
		}

??
??
??

3.3、operator[ ]

??1)、庫(kù)函數(shù)中聲明回顧

在這里插入圖片描述

??2)、模擬實(shí)現(xiàn)

T& operator[](size_t pos)//加&是為了支持可讀可寫(xiě)
		{	assert(pos< size());//檢查下標(biāo)是否非法
			return _start[pos];
		}


		const T& operator[](size_t pos)const
		{	assert(pos< size());
			return _start[pos];
		}

??
??

3.4、遍歷:迭代器(begin、end)、范圍for

在這里插入圖片描述

??1)、普通迭代器

//vector的迭代器就是原生指針
		iterator begin()
		{	return _start;
		}

		iterator end()
		{	return _finish;
		}

??
??
??2)、const修飾的迭代器
??為什么需要?
??存在如下的情況:const vector& v,所創(chuàng)建的vector對(duì)象被const修飾,如果直接使用vector::iterator it = v.begin();,則屬于權(quán)限放大。

typedef const T* const_iterator;

		const const_iterator begin()const
		{	return _start;
		}

		const const_iterator end()const
		{	return _finish;
		}
void Func(const vector& v)
	{vector::const_iterator it = v.begin();
		while (it != v.end())
		{	//*it = 10;//error
			cout<< *it<< " ";
			++it;
		}
		cout<< endl;

		for (auto e : v)//此處若使用范圍for,const對(duì)象會(huì)調(diào)用對(duì)應(yīng)的const迭代器
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

??
??3)、為什么說(shuō)范圍for是傻瓜式替換?
??只要我們仿照庫(kù)中使用對(duì)應(yīng)字符begin、end,則訪問(wèn)for就能起效。相應(yīng)的,如果我們使用了Begin、End等其它字母,則在我們模擬的vector中范圍for失效。
??
??

3.5、vector::insert、vector::erase 迭代器失效 3.5.1、vector::insert

??1)、庫(kù)函數(shù)中聲明回顧
在這里插入圖片描述

??2)、insert模擬實(shí)現(xiàn)1.0

void insert(iterator pos, const T& val)
		{	assert(pos<= _finish && pos >= _start);
			//擴(kuò)容檢查
			if (_finish == _end_of_storage)
			{		reserve(capacity() == 0 ? 4 : capacity() * 2);

			}
			//數(shù)據(jù)挪動(dòng)
			iterator end = _finish - 1;
			while (end >= pos)
			{		*(end + 1) = *end;
				end--;
			}
			//插入val值
			*pos = val;
			++_finish;
		}

在這里插入圖片描述
??
??
??3)、insert涉及擴(kuò)容時(shí)迭代器失效問(wèn)題
??問(wèn)題:

在這里插入圖片描述
??
??原因解釋:
在這里插入圖片描述
??
??
??4)、insert模擬實(shí)現(xiàn)2.0

??解決方案: 若擴(kuò)容,則要順帶更新pos指向位置

//保存二者指針差距
size_t len = pos - _start;
//擴(kuò)容后更新pos指向
pos = len + _start;
void insert(iterator pos, const T& val)
		{	assert(pos<= _finish && pos >= _start);
			//擴(kuò)容檢查
			if (_finish == _end_of_storage)
			{		//保存二者指針差距
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//擴(kuò)容后更新pos指向
				pos = len + _start;
			}

			//數(shù)據(jù)挪動(dòng)
			iterator end = _finish - 1;
			while (end >= pos)
			{		*(end + 1) = *end;
				end--;
			}
			//插入val值
			*pos = val;
			++_finish;
		}

在這里插入圖片描述
??
??
??

3.5.2、迭代器失效

??1)、問(wèn)題引入與現(xiàn)象分析
??接上一階段代碼,分析下述情形:
??一開(kāi)始我們使用find找到了p位置,然后在p位置前插入一次,現(xiàn)在我們變?yōu)閜位置前連續(xù)插入多次。問(wèn):是否能成功?

//使用算法中的find
		auto p = find(v.begin(), v.end(), 3);
		if (p != v.end())//找到了
		{	v.insert(p, 30);//1、插入一個(gè)30

			cout<< *p<< endl;//2、再次來(lái)到p的位置
			v.insert(p, 40);//3、我們p位置前插入一個(gè)40,問(wèn):是否能成功?
		}

??現(xiàn)象如下:

在這里插入圖片描述
??
??可能出現(xiàn)疑問(wèn)如下:我們?cè)?.5.1中解決了insert中pos位置更新的問(wèn)題,為什么此處p仍舊不起效?
??這里我們需要思考上述寫(xiě)的insert函數(shù)中,形參pos和實(shí)參p之間的關(guān)系??芍獣缘氖牵趇nsert函數(shù)中,它們是值傳遞,故形參改變不影響實(shí)參。

void insert(iterator pos, const T& val)
		{	assert(pos<= _finish && pos >= _start);
			//擴(kuò)容檢查
			if (_finish == _end_of_storage)
			{		//保存二者指針差距
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//擴(kuò)容后更新pos指向
				pos = len + _start;
			}

			//數(shù)據(jù)挪動(dòng)
			iterator end = _finish - 1;
			while (end >= pos)
			{		*(end + 1) = *end;
				end--;
			}
			//插入val值
			*pos = val;
			++_finish;
		}

??
??
??2)、解決方案
??①一個(gè)相對(duì)比較適合的方法是,在此類情況中,最好別再p位置失效后再去訪問(wèn)p。
??
??
??②有人可能提出,我們?cè)趇nsert中為pos加上一個(gè)引用,即傳引用返回,這樣不就解決了?void insert(iterator& pos, const T& val)

void insert(iterator& pos, const T& val)
		{	assert(pos<= _finish && pos >= _start);
			//擴(kuò)容檢查
			if (_finish == _end_of_storage)
			{		//保存二者指針差距
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//擴(kuò)容后更新pos指向
				pos = len + _start;
			}

			//數(shù)據(jù)挪動(dòng)
			iterator end = _finish - 1;
			while (end >= pos)
			{		*(end + 1) = *end;
				end--;
			}
			//插入val值
			*pos = val;
			++_finish;
		}

??事實(shí)上這樣做,針對(duì)insert而言確實(shí)可以解決問(wèn)題,但同樣會(huì)面臨新的問(wèn)題。
??第一,這樣的模擬實(shí)現(xiàn)與庫(kù)中不匹配,庫(kù)中直接使用iterator pos;
??第二,這樣做會(huì)帶來(lái)新的問(wèn)題,如下:

v.insert(v.begin(), 1);

??此段代碼無(wú)法編譯通過(guò)。因?yàn)閎egin模擬實(shí)現(xiàn)時(shí),我們使用的是iterator傳值返回,中間會(huì)生成一份臨時(shí)變量,具有常性,后續(xù)insert處權(quán)限放大。
????Ⅰ、若為insert加上const,那么又無(wú)法解決修改問(wèn)題。
????Ⅱ、而如果將begin也寫(xiě)為傳引用返回,iterator& begin(),這樣會(huì)使得begin具有修改能力,反而增添麻煩。

iterator begin()
		{	return _start;
		}

??
??
??3)、思考:上述值傳遞中,p一定存在迭代器失效問(wèn)題嗎?
??回答:同3.5.2中所講,在涉及擴(kuò)容問(wèn)題時(shí),p才存在失效。
??演示:如下述,假如我們一開(kāi)始插入5個(gè)數(shù)值,容量空間足夠的情況下,此處不存在p失效問(wèn)題。

在這里插入圖片描述

??
??
??4)、insert為push_back提供復(fù)用

void push_back(const T& x)
		{	insert(end(), x);
		}

??
??

??5)、insert模擬實(shí)現(xiàn)3.0:案例演示
??案例要求: 在所有的偶數(shù)前插入該偶數(shù)的二倍值。

??代碼演示+現(xiàn)象分析:
??我們以上述insert2.0版本為例進(jìn)行演示,順帶再來(lái)回顧一下迭代器失效問(wèn)題。

void test_vector5()
	{std::vectorv;
		v.reserve(10);
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//v.push_back(5);

		//在所有偶數(shù)前插入該偶數(shù)的2倍
		auto it = v.begin();
		while (it != v.end())
		{	if (*it % 2 == 0)
			{		v.insert(it, *it * 2);
			}
			++it;
		}
	}

??上述代碼我們直接運(yùn)行則程序崩潰無(wú)輸出結(jié)果,調(diào)試后發(fā)現(xiàn)如下:it始終指向2的位置。這就是迭代器失效的另一種模式:因?yàn)閿?shù)據(jù)挪動(dòng),導(dǎo)致外部指針指向錯(cuò)亂。
??ps: 迭代器失效的第一種模式:函數(shù)內(nèi)擴(kuò)容,導(dǎo)致野指針。
在這里插入圖片描述
??
??為了解決上述問(wèn)題,也一并解決insert中擴(kuò)容后外部迭代器失效問(wèn)題,一個(gè)方案如下:
????Ⅰ、對(duì)insert函數(shù),模仿庫(kù)中帶上iterator返回值;
????Ⅱ、對(duì)原先的二倍插入循環(huán),需要更新it指向的新位置,旨在解決擴(kuò)容后外部迭代器失效問(wèn)題。

iterator insert(iterator pos, const T& val)
		{	assert(pos<= _finish && pos >= _start);
			//擴(kuò)容檢查
			if (_finish == _end_of_storage)
			{		//保存二者指針差距
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//擴(kuò)容后更新pos指向
				pos = len + _start;
			}

			//數(shù)據(jù)挪動(dòng)
			iterator end = _finish - 1;
			while (end >= pos)
			{		*(end + 1) = *end;
				end--;
			}
			//插入val值
			*pos = val;
			++_finish;

			return pos;
		}
void test_vector5()
	{std::vectorv;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//v.push_back(5);

		//在所有偶數(shù)前插入該偶數(shù)的2倍
		auto it = v.begin();
		while (it != v.end())
		{	if (*it % 2 == 0)
			{		it=v.insert(it, *it * 2);
				++it;
			}
			++it;
		}
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

??演示結(jié)果:
在這里插入圖片描述

??
??
??

3.5.3、vector::erase

??1)、erase模擬實(shí)現(xiàn)1.0

void erase(iterator pos)
		{	assert(pos< _finish && pos >= _start);
			iterator end = pos + 1;
			while (end< _finish)
			{		*(end - 1) = *end;
				++end;
			}
			--_finish;
		}

在這里插入圖片描述
??
??2)、erase是否會(huì)導(dǎo)致迭代器失效?
??①主要看編譯器如何實(shí)現(xiàn)erase函數(shù),不排除有些編譯器以時(shí)間換空間進(jìn)行縮容:
??

	if (size()< capacity()/2)
			{		// 縮容 -- 以時(shí)間換空間
			}

??
??
??②其它案例演示:刪除vector中的偶數(shù)
??使用代碼如下:

void erase(iterator pos)
		{	assert(pos< _finish && pos >= _start);
			iterator end = pos + 1;
			while (end< _finish)
			{		*(end - 1) = *end;
				++end;
			}
			--_finish;
		}
void test_vector4()
	{vectorv;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//v.push_back(5);
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;

		//刪除所有偶數(shù)
		auto it = v.begin();
		while (it != v.end())
		{	if(*it % 2 == 0)
			{		v.erase(it);
			}
			++it;
		}

		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

??現(xiàn)象如下:

在這里插入圖片描述??
??
??
??
??3)、erase模擬實(shí)現(xiàn)2.0

iterator erase(iterator pos)
		{	assert(pos< _finish && pos >= _start);
			iterator end = pos + 1;
			while (end< _finish)
			{		*(end - 1) = *end;
				++end;
			}
			--_finish;


			//if (size()< capacity()/2)
			//{	//	// 縮容 -- 以時(shí)間換空間
			//}

			return pos;
		}

??基于2.0版本的erase我們?cè)賮?lái)修改上述 2) 中的題目:

void test_vector4()
	{vectorv;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		//v.push_back(5);
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;

		//刪除所有偶數(shù)
		auto it = v.begin();
		while (it != v.end())
		{	if(*it % 2 == 0)
			{		it=v.erase(it);
			}
			else {		++it;
			}
		}

		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

??
??
??

3.5.5、細(xì)節(jié)問(wèn)題:不同編譯器下的迭代器失效

??需要注意的是,上述我們對(duì)迭代器失效的問(wèn)題演示,其結(jié)果是未定義的,因?yàn)獒槍?duì)不同平臺(tái)其STL底層實(shí)現(xiàn)并不一致。
??即,STL只是一個(gè)規(guī)范,其細(xì)節(jié)如何實(shí)現(xiàn)不做要求。
??VS:PJ版。
??g++:SGI版。
??
??

??

3.6、vector::resize

??1)、庫(kù)函數(shù)中聲明回顧
在這里插入圖片描述

??
??2)、模擬實(shí)現(xiàn)
??根據(jù)上述可知,resize面臨三種情況:
????Ⅰ、當(dāng)n>capacity:擴(kuò)容+使用val初始化;
????Ⅱ、當(dāng)size:使用val初始化;
????Ⅲ、當(dāng)n:刪除多余數(shù)據(jù)
??
??模擬實(shí)現(xiàn)如下:

void resize(size_t n, const T& val=T())
		{	if (n >capacity())
			{		reserve(n);
			}

			if (n >size())//兩種情況:n>capacity、size		//只需要初始化即可
				while (_finish< _start + n)
				{push_back(val);
					++_finish;
				}
			}
			else
			{		_finish = _start + n;
			}
		}

??演示驗(yàn)證一:

void test_vector11()
	{//resize常用場(chǎng)景:在生成對(duì)象后開(kāi)辟空間
		vectorv;
		v.resize(5);//驗(yàn)證默認(rèn)缺省值
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;

		v.resize(10, 2);
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

在這里插入圖片描述
??
??演示驗(yàn)證二:

void test_vector11()
	{vectorv1;
		v1.reserve(10);
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);

		v1.resize(8,8);//由大到小,而值只有5個(gè),會(huì)添3個(gè)值

		for (auto e : v1)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

在這里插入圖片描述
??
??
??
??

3.7、vector::front、vector::back

??1)、庫(kù)函數(shù)中聲明回顧
在這里插入圖片描述

??
??2)、模擬實(shí)現(xiàn)

T& front()
		{	assert(size() >0);
			return *_start;
		}

		T& back()
		{	assert(size() >0);
			return *(_finish - 1);
		}

??
??
??
??

4、拷貝構(gòu)造與賦值:vector的深拷貝問(wèn)題 4.1、深淺拷貝說(shuō)明

??1)、知識(shí)回顧
??在類和對(duì)象章節(jié),我們?cè)f(shuō)明:拷貝構(gòu)造對(duì)于內(nèi)置類型完成淺拷貝/值拷貝,對(duì)于自定義類型則會(huì)調(diào)用它對(duì)應(yīng)的拷貝構(gòu)造。
??
??
??2)、vector拷貝構(gòu)造分析
??vector的成員變量是內(nèi)置類型,故編譯器默認(rèn)生成的拷貝構(gòu)造函數(shù)完成的是淺拷貝。
??PS:typedef T* iterator;、此處盡管iterator是類模板,且T*會(huì)存在自定義類型的指針,但其仍舊是內(nèi)置類型。

private:
		iterator _start;//起始
		iterator _finish;//結(jié)束
		iterator _end_of_storage;//容量空間

??以如下代碼進(jìn)行拷貝構(gòu)造:

vectorv;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);

		vectorv2(v);

		for (auto e : v2)
		{	cout<< e<< " ";
		}
		cout<< endl;

在這里插入圖片描述
??淺拷貝帶來(lái)的兩個(gè)問(wèn)題:
????Ⅰ、析構(gòu)兩次
????Ⅱ、一個(gè)對(duì)象的修改,會(huì)影響另一個(gè)對(duì)象
??
??
??

4.2、vector拷貝構(gòu)造演示 4.2.1、寫(xiě)法一:自己開(kāi)辟空間,自己拷貝數(shù)據(jù)

??

vector(const vector& v)
		{	_start = new T[v.size()];//此處也可以開(kāi)辟v.capacity()大小的空間,各有各的優(yōu)缺點(diǎn)
			memcpy(_start, v._start, sizeof(T)*v.size());//照搬數(shù)據(jù)
			_finish = _start + v.size();
			_end_of_storage = _start + v.size();//此處this._finish的大小根據(jù)上述我們開(kāi)辟空間時(shí)的選擇而變動(dòng)
		}

??
??

4.2.2、寫(xiě)法二:復(fù)用
vector(const vector& v)
			:_start(nullptr)
			,_finish(nullptr)
			,_end_of_storage(nullptr)
		{	reserve(v.size());
			for (const auto& e : v)
			{		push_back(e);//this.push_back()
			}
		}

??
??
??

4.2.3、使用迭代器區(qū)間構(gòu)造構(gòu)造函數(shù)

??1)、vector構(gòu)造函數(shù):使用迭代器區(qū)間構(gòu)造1.0
??涉及問(wèn)題:
??Ⅰ、能否雙模板嵌套式使用?
??Ⅱ、為什么需要新定義一個(gè)模板InputIterator,而不使用原先的Iterator

templatevector(InputIterator first, InputIterator last)
		{	while (first != last)
			{		push_bakc(*first);
				++first;
			}
		}
void test_vector7()
	{string str("hello world");
		vectorv(str.begin(), str.end());//使用迭代器區(qū)間構(gòu)造
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

??上述代碼是否會(huì)存在什么問(wèn)題?
??回答:_start_finish、_end_of_storage沒(méi)有初始化,在有些編譯器下其是隨機(jī)值,那么reserve開(kāi)辟空間時(shí),此處非空就會(huì)拷貝數(shù)據(jù)、釋放空間、存在越界問(wèn)題。
在這里插入圖片描述

??
??2)、vector構(gòu)造函數(shù):使用迭代器區(qū)間構(gòu)造2.0

??_start、_finish、_end_of_storage初始化為空。

//使用迭代區(qū)間的構(gòu)造函數(shù):含類模板
		templatevector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	while (first != last)
			{		push_back(*first);
				++first;
			}
		}

在這里插入圖片描述

??
??

4.2.4、寫(xiě)法三:復(fù)用4.2.3、vector:: swap

在這里插入圖片描述

void swap(vector& v)
		{	std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v.__end_of_storage);
		}
vector(const vector& v)
			:_start(nullptr)
			,_finish(nullptr)
			,_end_of_storage(nullptr)
		{	vectortmp(v.begin(), v.end());
			swap(tmp);
		}

??

??
??
??

4.2.5、構(gòu)造函數(shù):n個(gè)val值

??1)、模擬實(shí)現(xiàn)及細(xì)節(jié)解析

vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	reserve(n);
			for (size_t i = 0; i< n; ++i)
			{		push_back(val);
			}
		}

??對(duì)const T& val = T(),實(shí)際上這個(gè)函數(shù)使用了半缺省參數(shù),其缺省值是T(),一個(gè)T類型的匿名對(duì)象。
????Ⅰ、假若T()是自定義類型,則調(diào)用自定義類型的默認(rèn)構(gòu)造(事實(shí)上內(nèi)置類型也有模板參數(shù))
????Ⅱ、假若T()是內(nèi)置類型,因C++中模板的出現(xiàn),也擁有對(duì)應(yīng)的默認(rèn)構(gòu)造函數(shù),此處以int舉例。

void test_vector9()
	{int i=11;
		int j = int();
		int k(10);
		cout<< "i:"<< i<< endl;
		cout<< "j:"<< j<< endl;
		cout<< "k:"<< k<< endl;

	}

在這里插入圖片描述

??
??
??2)、演示

void test_vector10()
	{vectorv1(10);//驗(yàn)證默認(rèn)缺省值

		for (auto e : v1)
		{	cout<< e<< " ";
		}
		cout<< endl;

		vectorv2(5);
		for (auto e : v2)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

在這里插入圖片描述

??
??
??3)、一個(gè)錯(cuò)誤說(shuō)明

vectorv1(10,1);//驗(yàn)證默認(rèn)缺省值

		for (auto e : v1)
		{	cout<< e<< " ";
		}
		cout<< endl;

??為什么在該函數(shù)中輸入兩個(gè)int類型的變量會(huì)顯示如下錯(cuò)誤,且報(bào)錯(cuò)還是報(bào)在我們之前寫(xiě)的迭代器區(qū)間構(gòu)造上?
在這里插入圖片描述
??原因解釋:類型匹配。相比于(size_tT)類型,(InputIteratorInputIterator)更匹配(int、int)。
??
??解決方法:
??①?gòu)?qiáng)制類型轉(zhuǎn)換:vectorv1(10u,1);
??②修改函數(shù)形參類型:vector(int n, const T& val = T())
??③使用函數(shù)重載:

vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	reserve(n);
			for (size_t i = 0; i< n; ++i)
			{		push_back(val);
			}
		}

??
??

4.3、vector賦值:operator=
//賦值v1=v2
		vector& operator=(vectorv)
		{	swap(v);
			return *this;
		}

在這里插入圖片描述
在這里插入圖片描述

??
??
??

4.4、二維數(shù)組下深淺拷貝問(wèn)題

??1)、問(wèn)題引入
??在vector(一)中,我們?cè)鴮?xiě)過(guò)楊輝三角:其涉及到了vector>嵌套使用。

class Solution {public:
    vector>generate(int numRows) {vector>vv;//定義一個(gè)vector>類型的數(shù)據(jù)
        vv.resize(numRows);//第一次開(kāi)辟空間:numRows,表示總行數(shù)(整體大小)
        for(size_t i=0;ivv[i].resize(i+1,0);//第二次開(kāi)辟空間,表示初始化楊輝三角的每行大小
            vv[i].front()=vv[i].back()=1;//楊輝三vv.size()角每行首尾數(shù)據(jù)為1

            //vv[i].resize(i+1,1);//上述代碼也可以合并為一行實(shí)現(xiàn)
        }

        for(size_t i=2;ifor(size_t j=1;jvv[i][j]=vv[i-1][j-1]+vv[i-1][j];
            }
        }

        return vv;
    }
};
vector>ret = Solution().generate(5);

??在使用std中的vector時(shí),這段代碼成功運(yùn)行。而將其放入我們自己實(shí)現(xiàn)的vector中,則會(huì)發(fā)現(xiàn)運(yùn)行失敗。
??為什么我們自己的模擬實(shí)現(xiàn)的vector會(huì)失敗呢?

??Ⅰ、對(duì)vector>generate(int numRows),如果我們不傳值返回ector>則運(yùn)行成功,而傳值返回運(yùn)行失敗。需要注意的是,此處傳值返回涉及自定義類型,存在數(shù)據(jù)拷貝的問(wèn)題。
??Ⅱ、基于此我們調(diào)試發(fā)現(xiàn):外層的vector深拷貝成功(值一致、地址空間不一致),而內(nèi)存的vector居然是淺拷貝。
在這里插入圖片描述

在這里插入圖片描述
??以上是現(xiàn)象,現(xiàn)在來(lái)分析情況:
??①自定義類型傳值返回,中間生成一個(gè)臨時(shí)變量,涉及深淺拷貝問(wèn)題。
??②拷貝構(gòu)造我們模擬實(shí)現(xiàn)了兩類,一類是傳統(tǒng)寫(xiě)法,使用了memcpy,由上述圖二可知,memcpy是淺拷貝,那么就涉及到同一空間析構(gòu)兩次的問(wèn)題。修改方法如下:

vector(const vector& v)//拷貝構(gòu)造傳統(tǒng)寫(xiě)法
		{	_start = new T[v.size()];//此處也可以開(kāi)辟v.capacity()大小的空間,各有各的優(yōu)缺點(diǎn)
			//memcpy(_start, v._start, sizeof(T)*v.size());//照搬數(shù)據(jù)
			for (size_t i = 0; i< sz; i++)//照搬數(shù)據(jù)
			{		_start[i] = v._start[i];//此處假若是自定義類型,則是賦值運(yùn)算符
			}
			_finish = _start + v.size();
			_end_of_storage = _start + v.size();//此處this._finish的大小根據(jù)上述我們開(kāi)辟空間時(shí)的選擇而變動(dòng)
		}

??③假若使用的是現(xiàn)代寫(xiě)法,在我們寫(xiě)的兩個(gè)以swap為交換的拷貝構(gòu)造,都沒(méi)問(wèn)題。此處出現(xiàn)問(wèn)題的是擴(kuò)容。原先我們寫(xiě)的擴(kuò)容函數(shù)中用了memcpy,同樣是淺拷貝導(dǎo)致。修改方法如下:

void reserve(size_t n)
		{	if (n >capacity())//滿足該條件才進(jìn)行擴(kuò)容
			{		size_t sz = size();//因?yàn)楹罄m(xù)重新確定指向關(guān)系時(shí)需要知道size值
				T* tmp = new T[n];
				if (_start)//說(shuō)明原先空間有數(shù)據(jù),
				{//memcpy(tmp, _start, sizeof(T) * sz);//需要挪動(dòng)
					for (size_t i = 0; i< sz; i++)//需要挪動(dòng)
					{tmp[i] = _start[i];
						//*(tmp + i) = *(_start + i);
					}
					delete[] _start;//釋放舊空間
				}
				//重新確定指向關(guān)系
				_start = tmp;
				_finish = _start + sz;
				//_finish = _start + size();//如果是在這里獲取size值,則在原先空間有數(shù)據(jù)的情況下,_start已經(jīng)被delete

				_end_of_storage = _start + n;
			}
		}

??
??
??
??
??
??
??
??
??

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

本文題目:【ONE·C++||vector(二)】-創(chuàng)新互聯(lián)
新聞來(lái)源:http://bm7419.com/article16/dsdedg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、企業(yè)網(wǎng)站制作、網(wǎng)站建設(shè)、定制網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)外貿(mào)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)