欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++模擬如何實(shí)現(xiàn)vector

 更新時間:2023年02月05日 17:03:49   作者:安河橋畔  
這篇文章主要介紹了C++模擬如何實(shí)現(xiàn)vector問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

一、迭代器

定義

vector類型的迭代器就是原生態(tài)的指針,對T*進(jìn)行重命名即可

typedef T* iterator;
typedef const T* const_iterator;

普通迭代器

iterator begin()
{
	return start;
}
iterator end()
{
	return finish;
}

const類型迭代器

const類型迭代器可以訪問const成員變量

const iterator cbegin()const
{
	return start;
}
const iterator cend()const
{
	return finish;
}

二、構(gòu)造類

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

構(gòu)造空對象

在初始化列表中對三個成員變量進(jìn)行初始化

vector()
	:start(nullptr)
	, finish(nullptr)
	, endOfStorage(nullptr)
{}

n個T類型

開辟空間以后,對finish進(jìn)行自增,在空間填充元素

vector(size_t n, const T& value = T())
	:start(new T[n])
	, finish(start)
	, endOfStorage(start + n)
{
	for (int i = 0; i < n; i++)
	{
		*finish++ = value;
	}
}

重載前一個構(gòu)造函數(shù),將第一個參數(shù)設(shè)置為int類型

vector(int n, const T& value = T())
	:start(new T[n])
	, finish(start)
	, endOfStorage(start + n)
{
	for (int i = 0; i < n; i++)
	{
		*finish++ = value;
	}
}

之所以要對這種類型的構(gòu)造函數(shù)進(jìn)行重載,是因?yàn)樵谡{(diào)用構(gòu)造函數(shù)時,如果實(shí)參傳兩個整型數(shù)字,編譯器會默認(rèn)為int類型數(shù)據(jù),進(jìn)行推演之后與前面的size_t類型不匹配,則會調(diào)用下面的區(qū)間構(gòu)造的方法,導(dǎo)致程序報(bào)錯,如圖:

迭代器構(gòu)造

將構(gòu)造方法中迭代器的類型寫成模板類型,這樣便可以接收其它類型的迭代器,如:T類型為char,Iterator迭代器為string類型,便可以從字符串中截取字符,構(gòu)造vector<char>類型的對象。

//寫成函數(shù)模板,可以接受任意類型的迭代器
template<typename Iterator>
vector(Iterator first, Iterator last)
{
	size_t n = ZH::distance(first, last);//獲取長度
	start = new T[n];
	finish = start;
	endOfStorage = start + n;
	while (first != last){
		*finish = *first;
		first++;
		finish++;//完成賦值的同時也移動了finish的位置
	}
}

將distance方法寫到另一個.hpp頭文件中

template<typename Iterator>
//此處的Iterator是模板參數(shù),表示可以傳任意類型的迭代器
size_t distance(Iterator first, Iterator last)
{
	//獲取元素個數(shù),暫時只考慮底層空間連續(xù)的情況
	int count = 0;
	while (first != last)
	{
		first++;
		count++;
	}
	return count;
}

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

拷貝構(gòu)造函數(shù)的形參必須是const類對象的引用,必須使用const類型的迭代器才能訪問,復(fù)用迭代器構(gòu)造的方法定義一個臨時變量temp,交換temp與當(dāng)前對象

//此處拷貝構(gòu)造函數(shù)的形參是const類型
vector(const vector<T>& v)
	:start(nullptr)
	, finish(nullptr)
	, endOfStorage(nullptr)
{
	//▲用const類型的迭代器訪問const變量
	vector<T> temp(v.cbegin(), v.cend());
	this->swap(temp);
}

賦值運(yùn)算符重載

形參設(shè)置為類類型對象,調(diào)用賦值運(yùn)算符重載函數(shù)時,形參會拷貝實(shí)參,交換當(dāng)前對象與形參的值。

vector<T>& operator=(const vector<T> v)
{
	this->swap(v);
	return *this;
}

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

釋放空間,將三個迭代器賦值為空

~vector()
{
	delete[]start;
	start = nullptr;
	finish = nullptr;
	endOfStorage = nullptr;
}

三、容量相關(guān)操作

size、capacity

size_t size()
{
	return finish - start;
}
size_t capacity()
{
	return endOfStorage - start;
}

empty

判斷fiinsh與start是否相等即可,相等則為空

size_t empty()
{
	return finish == start;
}

resize

定義一個變量保存舊的size的值‘判斷是減小還是增加size;判斷是否需要擴(kuò)容,需要則調(diào)用reserve函數(shù),從舊空間的結(jié)束位置開始,給新增加的空間填充元素;最后改變finish的值。

void resize(size_t newsize, const T& value = T())
{
	size_t oldsize = size();
	if (newsize > oldsize){
		if (newsize > capacity()){
			reserve(newsize);
		}
		for (size_t i = oldsize; i < newsize; i++)
		{
			start[i] = value;
		}
	}
	finish = start + newsize;//不用考慮增加或減小
}

?reserve

reserve的步驟:申請新空間,拷貝舊空間的元素,釋放舊的空間。

void reserve(size_t newcapacity)
{
	size_t oldcapacity = capacity();
	if (newcapacity > oldcapacity)
	{
		size_t n = size();//保存size()的值
		T* temp = new T[newcapacity];
		//start不為空時才進(jìn)行拷貝舊空間元素和釋放的操作
		if (start)
		{
			//memcpy淺拷貝,當(dāng)vector中存放的對象內(nèi)部設(shè)計(jì)資源管理
			// 會有內(nèi)存泄漏和野指針問題
			//memcpy(temp, start, sizeof(T) * n);

			for (size_t i = 0; i < n; i++)
			{
				temp[i] = start[i];//調(diào)用賦值運(yùn)算符重載
			}
			delete[] start;
		}
		start = temp;
		//▲此處不能用satart+size(),因?yàn)閟ize方法中有finish-start,而start值已經(jīng)改變
		finish = start + n;
		endOfStorage = start + newcapacity;
	}
}

▲易錯點(diǎn):

  • 判斷start的值是否為空 ,如果原來的start為空,則不需要再拷貝元素和釋放
  • 淺拷貝問題

finish更新問題

size()的方法內(nèi)部finish-start,而此時start已經(jīng)發(fā)生改變,finish還是舊的,所以要提前定義一個臨時變量保存size()的值

三、元素訪問

[ ]重載

重載成普通類型和const類型,const類型可以訪問const成員

T& operator[](size_t index)
{
	assert(index < size());
	return start[index];
}

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

front

返回動態(tài)數(shù)組第一個元素

T& front()
{
	return start[0];
}
const T& front()const
{
	return start[0];
}

back

返回最后一個位置前一個元素

T& back()
{
	return *(finish - 1);
}
const T& back()const
{
	return *(finish - 1);
}

四、修改類接口

push_back

插入前先判斷空間是否已滿,空間若滿則進(jìn)行擴(kuò)容,擴(kuò)容時,要原來的空間容量為0的情況;將value放置到末尾位置,并將finish向后移動一個單位

void push_back(const T& value)
{
	if (finish == endOfStorage)
	{
		//因?yàn)樵瓉淼腸apacity可能為0,所以要+3
		reserve(capacity() * 2 + 3);
	}
	*finish++ = value;
}

pop_back

尾刪,先判斷對象是否為空,若不為空則將finish位置前移一個單位

void pop_back()
{
	if (empty())
	{
		return;
	}
	finish--;
}

insert

任意位置插入,insert的返回值為新插入的第一個元素位置的迭代器;因?yàn)椴迦肟赡軙M(jìn)行擴(kuò)容,導(dǎo)致start的值改變,所以先定義一個變量保存pos與start的相對位置;判斷是否需要擴(kuò)容;從插入位置開始,將所有元素向后搬移一個位置;將pos位置的值置為要插入的值;更新finish的值。

//第二個參數(shù)用const修飾,常量引用
//不用const修飾則為非常量引用
iterator insert(iterator pos, const T& value)
{
	int index = pos - start;
	assert(pos >= start && pos < finish);
	//判斷空間是否足夠
	if (finish == endOfStorage)
	{
		reserve(capacity() * 2);
	}
	pos = start + index;
	for (auto it = finish; it > pos; it--)
	{
		*it = *(it - 1);
	}
	*pos = value;
	finish++;
	return pos;
}

erase

判斷下標(biāo)合法性;從pos位置下一個位置開始,將所有元素向前搬移一個位置;更新finish的值

iterator erase(iterator pos)
{
	assert(pos >= start && pos < finish);

	auto it = pos;
	while (it < finish - 1)
	{
		*it = *(it + 1);
		it++;
	}
	finish--;
	return pos;
}

clear

清空所有元素,令finish=start即可

void clear()
{
	finish = start;
}

swap

vector內(nèi)置的swap函數(shù),調(diào)用標(biāo)準(zhǔn)庫中的swap交換vector的三個成員變量的值

void swap(vector<T>& v)
{
	std::swap(start, v.start);
	std::swap(finish, v.finish);
	std::swap(endOfStorage, v.endOfStorage);
}

五、成員變量

private:
	iterator start;
	iterator finish;
	iterator endOfStorage;

vector內(nèi)部有三個成員變量,start表示起始位置,finish表示有效元素的末尾位置,endOfStorage表示空間的末尾位置;通過這三個成員變量可以得到size和capacity等值,如圖:

總結(jié)

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++實(shí)現(xiàn)簡單走迷宮的代碼

    C++實(shí)現(xiàn)簡單走迷宮的代碼

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡單走迷宮的代碼,利用回溯法求解,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 關(guān)于C++使用std::chrono獲取當(dāng)前秒級/毫秒級/微秒級/納秒級時間戳問題

    關(guān)于C++使用std::chrono獲取當(dāng)前秒級/毫秒級/微秒級/納秒級時間戳問題

    這篇文章主要介紹了C++使用std::chrono獲取當(dāng)前秒級/毫秒級/微秒級/納秒級時間戳,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • C++中測試程序運(yùn)行時間的幾種方法總結(jié)

    C++中測試程序運(yùn)行時間的幾種方法總結(jié)

    本文介紹了C++中測量程序運(yùn)行時間的幾種方法,包括使用GetTickCount()、clock()、Boost庫的timer類以及高精度時控函數(shù)QueryPerformanceFrequency和QueryPerformanceCounter,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • C++使用TinyXml實(shí)現(xiàn)讀取XMl文件

    C++使用TinyXml實(shí)現(xiàn)讀取XMl文件

    常見C/C++?XML解析器有Tinyxml、XERCES、squashxml、xmlite、pugxml、libxml等等,本文為大家介紹的是使用TinyXml實(shí)現(xiàn)讀取XMl文件,需要的可以參考一下
    2023-06-06
  • C語言深入探究選擇排序與基數(shù)排序使用案例講解

    C語言深入探究選擇排序與基數(shù)排序使用案例講解

    算法中排序是十分重要的,而每一個學(xué)習(xí)計(jì)算機(jī)的都會在初期的時候接觸到這種排序,下面這篇文章主要給大家介紹了關(guān)于c語言選擇排序與基數(shù)排序使用的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • C語言 存儲類詳解及示例代碼

    C語言 存儲類詳解及示例代碼

    本篇文章主要介紹C語言 存儲類,這里幫大家整理了存儲類的基礎(chǔ)資料,并提供示例代碼和詳細(xì)介紹,有興趣的小伙伴可以參考下
    2016-08-08
  • C++用mysql自帶的頭文件連接數(shù)據(jù)庫

    C++用mysql自帶的頭文件連接數(shù)據(jù)庫

    現(xiàn)在正做一個接口,通過不同的連接字符串操作不同的數(shù)據(jù)庫。要用到mysql數(shù)據(jù)庫。通過網(wǎng)上的一些資料和自己的摸索,大致清楚了C++連接mysql的方法??梢酝ㄟ^2種方法實(shí)現(xiàn)。第一種方法是利用ADO連接,第二種方法是利用mysql自己的api函數(shù)進(jìn)行連接。今天主要來講解下使用API
    2016-07-07
  • C語言代碼實(shí)現(xiàn)通訊錄管理系統(tǒng)

    C語言代碼實(shí)現(xiàn)通訊錄管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言代碼實(shí)現(xiàn)通訊錄管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C++中需要注意的細(xì)節(jié)你知道嗎

    C++中需要注意的細(xì)節(jié)你知道嗎

    這篇文章主要介紹了C++ 需要注意的幾點(diǎn)細(xì)節(jié),幫助大家更好的理解和學(xué)習(xí)C++,感興趣的朋友可以了解下,希望能夠給你帶來幫助
    2021-09-09
  • C++野指針和懸空指針的實(shí)現(xiàn)方法

    C++野指針和懸空指針的實(shí)現(xiàn)方法

    野指針和懸空指針是指針中常見的兩個概念,本文詳細(xì)的介紹了這兩種的使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論