bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

【ONE·C++||vector(二)】-創新互聯

總言

??主要講述vector的模擬實現。

創新互聯專注于木蘭網站建設服務及定制,我們擁有豐富的企業做網站經驗。 熱誠為您提供木蘭營銷型網站建設,木蘭網站制作、木蘭網頁設計、木蘭網站官網定制、微信小程序服務,打造木蘭網絡公司原創品牌,更為您提供木蘭網站排名全網營銷落地服務。文章目錄
  • 總言
  • 1、基本框架搭建:成員變量
  • 2、對構造函數、析構函數
  • 3、增刪查改、空間擴容
    • 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、細節問題:不同編譯器下的迭代器失效
    • 3.6、vector::resize
    • 3.7、vector::front、vector::back
  • 4、拷貝構造與賦值:vector的深拷貝問題
    • 4.1、深淺拷貝說明
    • 4.2、vector拷貝構造演示
      • 4.2.1、寫法一:自己開辟空間,自己拷貝數據
      • 4.2.2、寫法二:復用
      • 4.2.3、使用迭代器區間構造構造函數
      • 4.2.4、寫法三:復用4.2.3、vector:: swap
      • 4.2.5、構造函數:n個val值
    • 4.3、vector賦值:operator=
    • 4.4、二維數組下深淺拷貝問題

??

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

??同string類模擬實現一致,此處為了解決命名沖突問題,我們使用添加命名空間myvector的方式來處理。

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

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

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

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

??
??

2、對構造函數、析構函數

??1)、構造函數
??對構造函數,我們之前學習時看到其中有內存池的相關內容,此處由于我們暫時沒學習它,故對vector的模擬實現中我們不使用它。

vector() //構造函數
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

??
??2)、析構函數

~vector()//析構函數
		{	delete[] _start;//null出來的空間是連續一塊的,以_start為起始點。注意delete的使用方式
			_start = _finish = _end_of_storage = nullptr;
		}

??
??

3、增刪查改、空間擴容 3.1、vector::push_back、vector::pop_back

??1)、庫函數中聲明回顧

??2)、push_back模擬實現

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

		}

??為什么需要使用引用和const修飾?
??因為這里使用的是T模板參數,我們傳入的值可能是內置類型,也可能是自定義類型,如果是后者,則傳值傳參代價很大。
??
??3)、pop_back模擬實現

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

??
??
??
??

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

??1)、庫函數中聲明回顧

在這里插入圖片描述

??2)、模擬實現

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


		size_t capacity()const
		{	return _end_of_storage - _start;
		}
void reserve(size_t n)
		{	if (n >capacity())//滿足該條件才進行擴容
			{		size_t sz = size();//因為后續重新確定指向關系時需要知道size值
				T* tmp = new T[n];
				if (_start)//說明原先空間有數據,
				{memcpy(tmp, _start, sizeof(T) * sz);//需要挪動
					delete[] _start;//釋放舊空間
				}
				//重新確定指向關系
				_start = tmp;
				_finish = _start + sz;
				//_finish = _start + size();//如果是在這里獲取size值,則在原先空間有數據的情況下,_start已經被delete

				_end_of_storage = _start + n;
			}
		}

??
??
??

3.3、operator[ ]

??1)、庫函數中聲明回顧

在這里插入圖片描述

??2)、模擬實現

T& operator[](size_t pos)//加&是為了支持可讀可寫
		{	assert(pos< size());//檢查下標是否非法
			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,所創建的vector對象被const修飾,如果直接使用vector::iterator it = v.begin();,則屬于權限放大。

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對象會調用對應的const迭代器
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

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

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

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

??2)、insert模擬實現1.0

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

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

在這里插入圖片描述
??
??
??3)、insert涉及擴容時迭代器失效問題
??問題:

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

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

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

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

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

3.5.2、迭代器失效

??1)、問題引入與現象分析
??接上一階段代碼,分析下述情形:
??一開始我們使用find找到了p位置,然后在p位置前插入一次,現在我們變為p位置前連續插入多次。問:是否能成功?

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

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

??現象如下:

在這里插入圖片描述
??
??可能出現疑問如下:我們在3.5.1中解決了insert中pos位置更新的問題,為什么此處p仍舊不起效?
??這里我們需要思考上述寫的insert函數中,形參pos和實參p之間的關系。可知曉的是,在insert函數中,它們是值傳遞,故形參改變不影響實參。

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

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

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

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

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

??事實上這樣做,針對insert而言確實可以解決問題,但同樣會面臨新的問題。
??第一,這樣的模擬實現與庫中不匹配,庫中直接使用iterator pos
??第二,這樣做會帶來新的問題,如下:

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

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

iterator begin()
		{	return _start;
		}

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

在這里插入圖片描述

??
??
??4)、insert為push_back提供復用

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

??
??

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

??代碼演示+現象分析:
??我們以上述insert2.0版本為例進行演示,順帶再來回顧一下迭代器失效問題。

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);

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

??上述代碼我們直接運行則程序崩潰無輸出結果,調試后發現如下:it始終指向2的位置。這就是迭代器失效的另一種模式:因為數據挪動,導致外部指針指向錯亂。
??ps: 迭代器失效的第一種模式:函數內擴容,導致野指針。
在這里插入圖片描述
??
??為了解決上述問題,也一并解決insert中擴容后外部迭代器失效問題,一個方案如下:
????Ⅰ、對insert函數,模仿庫中帶上iterator返回值;
????Ⅱ、對原先的二倍插入循環,需要更新it指向的新位置,旨在解決擴容后外部迭代器失效問題。

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

			//數據挪動
			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);

		//在所有偶數前插入該偶數的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;
	}

??演示結果:
在這里插入圖片描述

??
??
??

3.5.3、vector::erase

??1)、erase模擬實現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是否會導致迭代器失效?
??①主要看編譯器如何實現erase函數,不排除有些編譯器以時間換空間進行縮容:
??

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

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

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;

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

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

??現象如下:

在這里插入圖片描述??
??
??
??
??3)、erase模擬實現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)
			//{	//	// 縮容 -- 以時間換空間
			//}

			return pos;
		}

??基于2.0版本的erase我們再來修改上述 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;

		//刪除所有偶數
		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、細節問題:不同編譯器下的迭代器失效

??需要注意的是,上述我們對迭代器失效的問題演示,其結果是未定義的,因為針對不同平臺其STL底層實現并不一致。
??即,STL只是一個規范,其細節如何實現不做要求。
??VS:PJ版。
??g++:SGI版。
??
??

??

3.6、vector::resize

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

??
??2)、模擬實現
??根據上述可知,resize面臨三種情況:
????Ⅰ、當n>capacity:擴容+使用val初始化;
????Ⅱ、當size:使用val初始化;
????Ⅲ、當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;
			}
		}

??演示驗證一:

void test_vector11()
	{//resize常用場景:在生成對象后開辟空間
		vectorv;
		v.resize(5);//驗證默認缺省值
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;

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

在這里插入圖片描述
??
??演示驗證二:

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個,會添3個值

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

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

3.7、vector::front、vector::back

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

??
??2)、模擬實現

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

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

??
??
??
??

4、拷貝構造與賦值:vector的深拷貝問題 4.1、深淺拷貝說明

??1)、知識回顧
??在類和對象章節,我們曾說明:拷貝構造對于內置類型完成淺拷貝/值拷貝,對于自定義類型則會調用它對應的拷貝構造。
??
??
??2)、vector拷貝構造分析
??vector的成員變量是內置類型,故編譯器默認生成的拷貝構造函數完成的是淺拷貝。
??PS:typedef T* iterator;、此處盡管iterator是類模板,且T*會存在自定義類型的指針,但其仍舊是內置類型。

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

??以如下代碼進行拷貝構造:

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;

在這里插入圖片描述
??淺拷貝帶來的兩個問題:
????Ⅰ、析構兩次
????Ⅱ、一個對象的修改,會影響另一個對象
??
??
??

4.2、vector拷貝構造演示 4.2.1、寫法一:自己開辟空間,自己拷貝數據

??

vector(const vector& v)
		{	_start = new T[v.size()];//此處也可以開辟v.capacity()大小的空間,各有各的優缺點
			memcpy(_start, v._start, sizeof(T)*v.size());//照搬數據
			_finish = _start + v.size();
			_end_of_storage = _start + v.size();//此處this._finish的大小根據上述我們開辟空間時的選擇而變動
		}

??
??

4.2.2、寫法二:復用
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、使用迭代器區間構造構造函數

??1)、vector構造函數:使用迭代器區間構造1.0
??涉及問題:
??Ⅰ、能否雙模板嵌套式使用?
??Ⅱ、為什么需要新定義一個模板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());//使用迭代器區間構造
		for (auto e : v)
		{	cout<< e<< " ";
		}
		cout<< endl;
	}

??上述代碼是否會存在什么問題?
??回答:_start_finish_end_of_storage沒有初始化,在有些編譯器下其是隨機值,那么reserve開辟空間時,此處非空就會拷貝數據、釋放空間、存在越界問題。
在這里插入圖片描述

??
??2)、vector構造函數:使用迭代器區間構造2.0

??_start_finish_end_of_storage初始化為空。

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

在這里插入圖片描述

??
??

4.2.4、寫法三:復用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、構造函數:n個val值

??1)、模擬實現及細節解析

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);
			}
		}

??對const T& val = T(),實際上這個函數使用了半缺省參數,其缺省值是T(),一個T類型的匿名對象。
????Ⅰ、假若T()是自定義類型,則調用自定義類型的默認構造(事實上內置類型也有模板參數)
????Ⅱ、假若T()是內置類型,因C++中模板的出現,也擁有對應的默認構造函數,此處以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);//驗證默認缺省值

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

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

在這里插入圖片描述

??
??
??3)、一個錯誤說明

vectorv1(10,1);//驗證默認缺省值

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

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

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、二維數組下深淺拷貝問題

??1)、問題引入
??在vector(一)中,我們曾寫過楊輝三角:其涉及到了vector>嵌套使用。

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

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

        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時,這段代碼成功運行。而將其放入我們自己實現的vector中,則會發現運行失敗。
??為什么我們自己的模擬實現的vector會失敗呢?

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

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

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

??③假若使用的是現代寫法,在我們寫的兩個以swap為交換的拷貝構造,都沒問題。此處出現問題的是擴容。原先我們寫的擴容函數中用了memcpy,同樣是淺拷貝導致。修改方法如下:

void reserve(size_t n)
		{	if (n >capacity())//滿足該條件才進行擴容
			{		size_t sz = size();//因為后續重新確定指向關系時需要知道size值
				T* tmp = new T[n];
				if (_start)//說明原先空間有數據,
				{//memcpy(tmp, _start, sizeof(T) * sz);//需要挪動
					for (size_t i = 0; i< sz; i++)//需要挪動
					{tmp[i] = _start[i];
						//*(tmp + i) = *(_start + i);
					}
					delete[] _start;//釋放舊空間
				}
				//重新確定指向關系
				_start = tmp;
				_finish = _start + sz;
				//_finish = _start + size();//如果是在這里獲取size值,則在原先空間有數據的情況下,_start已經被delete

				_end_of_storage = _start + n;
			}
		}

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

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

本文題目:【ONE·C++||vector(二)】-創新互聯
新聞來源:http://vcdvsql.cn/article16/dsdedg.html

成都網站建設公司_創新互聯,為您提供微信公眾號企業網站制作網站建設定制網站品牌網站設計外貿網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯