目錄
一、定義
二、模擬實(shí)現(xiàn)
1、無參初始化
2、size&capacity
3、reserve
4、push_back
5、迭代器
6、empty
7、pop_back
8、operator[ ]
9、resize
10、insert
迭代器失效問題
11、erase
12、帶參初始化
13、迭代器初始化
14、析構(gòu)函數(shù)
15、深拷貝
16、賦值運(yùn)算符重載
完整版代碼&測試代碼
一、定義
本次參考SGI版本STL中的vector模擬實(shí)現(xiàn)。
我們可以看到上述源代碼中,SGI版本vector是借助指針實(shí)現(xiàn)的,元素的處理是通過兩個(gè)指針來實(shí)現(xiàn)的,而不是三個(gè)迭代器。這兩個(gè)指針分別是_start和_finish。
- _start指針指向vector中的第一個(gè)元素。
- _finish指針指向vector中最后一個(gè)元素的下一個(gè)位置。
通過_start和_finish指針,可以確定vector中存儲(chǔ)的元素范圍。
?
此外,SGI版本的vector還使用了一個(gè)指針_end_of_storage來表示vector分配的內(nèi)存空間的末尾位置。
這些指針的使用使得SGI版本的vector能夠高效地進(jìn)行元素的插入、刪除和訪問操作。
為了不影響VS中STL庫已有的vector,我們選擇將模擬實(shí)現(xiàn)的vector放在自定義命名空間中。
namespace byte
{
template<class T>
class vector
{
public:
private:
iterator _start;
iterator _finish;
iterator _end_of_storage;
};
}
二、模擬實(shí)現(xiàn)
1、無參初始化
vector()
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
2、size&capacity
size_t capacity() const
{
return _end_of_storage - _start;
}
size_t size() const
{
return _finish - _start;
}
3、reserve
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
-
if (n > capacity())
:檢查傳入的n是否大于當(dāng)前vector的容量。如果是,則需要進(jìn)行內(nèi)存重新分配。 -
size_t sz = size();
:保存當(dāng)前vector的大?。ㄔ貍€(gè)數(shù))。 -
T* tmp = new T[n];
:創(chuàng)建一個(gè)新的大小為n的動(dòng)態(tài)數(shù)組tmp,用于存儲(chǔ)重新分配后的元素。 -
if (_start)
:檢查_start指針判斷舊空間是否為非空。如果_start指針不為空,說明vector中已經(jīng)有元素存儲(chǔ)在舊的內(nèi)存空間中。 -
memcpy(tmp, _start, sizeof(T) * size());
:使用memcpy函數(shù)將舊的內(nèi)存空間中的元素復(fù)制到新的內(nèi)存空間tmp中。這樣可以保留元素的值。 -
delete[] _start;
:釋放舊的內(nèi)存空間。 -
_start = tmp;
:將_start指針指向新的內(nèi)存空間tmp。 -
_finish = _start + sz;
:更新_finish指針,使其指向新的內(nèi)存空間中的最后一個(gè)元素的下一個(gè)位置。 -
_end_of_storage = _start + n;
:更新_end_of_storage指針,使其指向新的內(nèi)存空間的末尾位置。?
對(duì)上述函數(shù)進(jìn)行改進(jìn):
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*size());
for (size_t i = 0; i < sz; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
第二個(gè)函數(shù)的改進(jìn)在于它使用了元素級(jí)別的復(fù)制(通過賦值操作符)而不是直接內(nèi)存復(fù)制(通過memcpy
)。
在第一個(gè)函數(shù)中,memcpy
直接復(fù)制了內(nèi)存塊,這對(duì)于平凡的數(shù)據(jù)類型(如整數(shù)、浮點(diǎn)數(shù)、字符等)是沒有問題的,因?yàn)檫@些類型的復(fù)制就是簡單的內(nèi)存復(fù)制。然而,對(duì)于包含自定義復(fù)制行為的類類型,memcpy
可能會(huì)導(dǎo)致錯(cuò)誤,因?yàn)樗粫?huì)調(diào)用類的復(fù)制構(gòu)造函數(shù)或賦值操作符。
在第二個(gè)函數(shù)中,通過循環(huán)和賦值操作符進(jìn)行元素級(jí)別的復(fù)制。這樣,如果T
是一個(gè)類類型,并且定義了自定義的復(fù)制構(gòu)造函數(shù)或賦值操作符,那么這些函數(shù)將被正確調(diào)用,從而避免了可能的錯(cuò)誤。
因此,第二個(gè)函數(shù)的改進(jìn)在于它更安全,更適合處理包含自定義復(fù)制行為的類類型。
4、push_back
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
++_finish;
}
-
使用
const T& x
作為參數(shù)類型可以避免不必要的拷貝操作,因?yàn)閭魅氲膶?shí)參可以直接通過引用訪問,而不需要進(jìn)行拷貝構(gòu)造。這可以提高性能和效率,特別是當(dāng)處理大型對(duì)象時(shí)。另外,使用
const T& x
還可以確保傳入的元素不會(huì)被修改,因?yàn)?code>const關(guān)鍵字表示傳入的引用是只讀的,函數(shù)內(nèi)部不能修改傳入的對(duì)象。 -
if (_finish == _end_of_storage)
?這個(gè)條件判斷用于檢查當(dāng)前vector是否已經(jīng)達(dá)到了內(nèi)存空間的末尾。如果是,則需要進(jìn)行內(nèi)存重新分配。 -
reserve(capacity() == 0 ? 4 : capacity() * 2)
?在需要進(jìn)行內(nèi)存重新分配時(shí),調(diào)用reserve
函數(shù)來預(yù)留更多的內(nèi)存空間。這里使用了三目運(yùn)算符,如果當(dāng)前容量為0,則預(yù)留4個(gè)元素的空間,否則將當(dāng)前容量乘以2來預(yù)留更多的空間。 -
*_finish = x
?將傳入的元素x
賦值給_finish
指針?biāo)赶虻奈恢?,即在vector的末尾插入元素。 -
++_finish
?將_finish
指針向后移動(dòng)一位,指向新插入元素的下一個(gè)位置,以便維護(hù)vector的邊界。
5、迭代器
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
- 首先,通過
typedef
關(guān)鍵字,定義了兩個(gè)迭代器類型:iterator
和const_iterator
。iterator
表示可修改元素的迭代器,而const_iterator
表示只讀元素的迭代器。 - 然后,定義了
begin()
和end()
函數(shù)的多個(gè)重載版本,用于返回不同類型的迭代器。
6、empty
bool empty()
{
return _start == _finish;
}
7、pop_back
void pop_back(const T& x)
{
assert(!empty());
--_finish;
}
8、operator[ ]
這個(gè)類中有兩個(gè)重載的下標(biāo)運(yùn)算符函數(shù),一個(gè)是非常量版本的?operator[]
,另一個(gè)是常量版本的?operator[]
。這是為了支持對(duì)類對(duì)象的讀寫操作和只讀操作的區(qū)分。
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
9、resize
void resize(size_t n, T val = T())
{
if (n < size())
{
_finish = _start + n;
}
else {
if (n < capacity())
reserve(n);
while (_finish != _start + n)
{
*_finish = val;
++_finish;
}
}
}
函數(shù)簽名為?
void resize(size_t n, T val = T())
,接受兩個(gè)參數(shù):n
?表示新的大小,val
?表示新元素的默認(rèn)值(默認(rèn)為?T()
,通過匿名對(duì)象T()調(diào)用類型?T
?的默認(rèn)構(gòu)造函數(shù))。
函數(shù)的作用是將容器的大小調(diào)整為?n
。如果?n
?小于當(dāng)前的大小,則將容器的大小縮小為?n
,丟棄多余的元素;如果?n
?大于當(dāng)前的大小,則在容器的末尾添加新的元素,直到容器的大小達(dá)到?n
。
- 首先,函數(shù)會(huì)檢查?n?是否小于當(dāng)前的大小。如果是,說明需要縮小容器的大小,將?_finish?指針移動(dòng)到新的位置?_start + n,丟棄多余的元素。
- 如果?n?大于等于當(dāng)前的大小,則需要添加新的元素。首先,函數(shù)會(huì)檢查?n?是否大于容器的容量?capacity()。如果?n?大于容量,則調(diào)用?reserve?函數(shù)來增加容器的容量,以確保容器有足夠的空間來存放新的元素。
- 然后,使用循環(huán)將新的元素?val?添加到容器的末尾,直到容器的大小達(dá)到?n。循環(huán)中,將?val?賦值給?_finish?指向的位置,然后將?_finish?指針向后移動(dòng)一位。
匿名對(duì)象調(diào)用默認(rèn)構(gòu)造初始化。
template<class T>
void f()
{
T x = T();
cout << x << endl;
}
- 在?
resize
?函數(shù)中,T val = T()
?是一個(gè)帶有默認(rèn)值的函數(shù)參數(shù)。這里?T()
?是對(duì)模板參數(shù)?T
?類型的值初始化,對(duì)于內(nèi)置類型,它會(huì)初始化為零(對(duì)于指針類型,初始化為?nullptr
)。這和?f<T>()
?模板函數(shù)中的?T x = T()
?是一樣的。 - 當(dāng)你調(diào)用?
resize
?函數(shù)時(shí),如果你沒有提供第二個(gè)參數(shù),那么?val
?就會(huì)被初始化為?T
?類型的默認(rèn)值。然后,resize
?函數(shù)會(huì)使用?val
?的值來填充新添加的元素。 - 例如,如果你有一個(gè)?
byte::vector<int>
?對(duì)象?v
,并調(diào)用?v.resize(10)
,那么?resize
?函數(shù)會(huì)將?v
?的大小改變?yōu)?10
,并使用?int
?類型的默認(rèn)值?0
?來填充新添加的元素。這和?f<int>()
?函數(shù)打印?int
?類型的默認(rèn)值?0
?是一樣的。
?內(nèi)置類型的默認(rèn)初始化和直接初始化。
void test_vector2()
{
// 內(nèi)置類型有沒有構(gòu)造函數(shù)
int i = int();
int j = int(1);
f<int>();
f<int*>();
f<double>();
}
-
int i = int();?使用值初始化,將?i?初始化為零。int j = int(1);?使用直接初始化,將?j?初始化為?1。
-
分別使用?int、int* 和?double?作為模板參數(shù)調(diào)用了?f<T>()?函數(shù)。這將分別打印?int、int* 和?double?類型的默認(rèn)值,即?0、nullptr?和?0。
10、insert
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
// 擴(kuò)容后更新pos,解決pos失效的問題
pos = _start + len;
}
iterator end = _finish-1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = val;
++_finish;
return pos;
}
函數(shù)接受兩個(gè)參數(shù),第一個(gè)參數(shù)?pos
?是一個(gè)迭代器,表示要插入元素的位置,第二個(gè)參數(shù)?val
?是要插入的元素的值。
函數(shù)的實(shí)現(xiàn)分為以下幾個(gè)步驟:
-
首先,使用?
assert
?斷言來確保?pos
?是一個(gè)有效的位置,即?pos
?必須在?_start
?和?_finish
?之間。 -
然后,檢查是否有足夠的空間來插入新的元素。如果?
_finish
?等于?_end_of_storage
,表示當(dāng)前的內(nèi)存已經(jīng)用完,需要重新分配內(nèi)存。這時(shí),會(huì)調(diào)用?reserve
?函數(shù)來重新分配內(nèi)存,新的容量是當(dāng)前容量的兩倍,如果當(dāng)前容量為?0
,則新的容量為?4
。然后,更新?pos
?的值,因?yàn)橹匦路峙鋬?nèi)存后,原來的?pos
?可能已經(jīng)失效。 -
接下來,從?
_finish-1
?開始,將每個(gè)元素向后移動(dòng)一位,直到?pos
?的位置,為插入新的元素騰出空間。 -
然后,將?
val
?的值賦給?*pos
,即在?pos
?的位置插入新的元素。 -
最后,將?
_finish
?向后移動(dòng)一位,表示?vector
?的大小增加了一個(gè)元素。 -
函數(shù)返回插入新元素的位置?
pos
。
迭代器失效問題
- 在 `byte::vector` 類的 `insert` 函數(shù)中,如果需要重新分配內(nèi)存(即 `_finish+ + == _end_of_storage`),那么所有指向原來內(nèi)存的迭代器都會(huì)失效。這是因?yàn)?`reserve` 函數(shù)會(huì)申請(qǐng)新的內(nèi)存,復(fù)制原來的元素到新的內(nèi)存,然后釋放原來的內(nèi)存。這個(gè)過程會(huì)導(dǎo)致原來的內(nèi)存地址不再有效,因此所有指向原來內(nèi)存的迭代器都會(huì)失效。
- 在這個(gè)函數(shù)中,`pos` 是一個(gè)迭代器,它指向要插入新元素的位置。如果在插入新元素之前需要重新分配內(nèi)存,那么 `pos` 就會(huì)失效。為了解決這個(gè)問題,函數(shù)在重新分配內(nèi)存后,會(huì)根據(jù) `pos` 原來的位置(即 `len = pos - _start`)來更新 `pos` 的值(即 `pos = _start + len`)。這樣,`pos` 就會(huì)指向新內(nèi)存中相同的位置。
- 所以,如果你在調(diào)用 `insert` 函數(shù)之后還需要使用原來的迭代器,你需要注意迭代器可能已經(jīng)失效。你可以在插入新元素后,重新獲取迭代器的值。例如,如果你在插入新元素后,想要訪問新元素,這里不能常量pos使用引用傳值,你可以使用 `insert` 函數(shù)的返回值,它返回的是插入新元素的位置。這時(shí)外部插入元素后? (*pos)++; 可以正常運(yùn)行了。
11、erase
我們先看這個(gè)版本的erase:
void erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator start = pos + 1;
while (start != _finish)
{
*(start - 1) = *start;
++start;
}
--_finish;
}
?當(dāng)我們運(yùn)行以下代碼程序VS會(huì)報(bào)錯(cuò),linux下g++不會(huì)報(bào)錯(cuò)。
void test4()
{
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
auto pos = find(v1.begin(), v1.end(), 2);
if (pos != v1.end())
{
v1.erase(pos);
}
(*pos)++;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
}
VS下:?
g++下:
這段代碼中,v1.erase(pos)
?會(huì)刪除?vector
?中的一個(gè)元素,這會(huì)導(dǎo)致?pos
?以及所有在?pos
?之后的迭代器失效。然后,代碼試圖通過?(*pos)++
?訪問和修改已經(jīng)失效的迭代器?pos
,這是未定義行為,可能會(huì)導(dǎo)致程序崩潰或其他錯(cuò)誤。
至于為什么 Visual Studio(VS) 會(huì)報(bào)錯(cuò),而 g++ 不會(huì)報(bào)錯(cuò),這主要是因?yàn)椴煌木幾g器對(duì)未定義行為的處理方式不同。VS 的調(diào)試模式下對(duì)迭代器進(jìn)行了更嚴(yán)格的檢查,當(dāng)你試圖訪問失效的迭代器時(shí),它會(huì)立即報(bào)錯(cuò)。而 g++ 在默認(rèn)設(shè)置下可能不會(huì)進(jìn)行這樣的檢查,所以它可能不會(huì)立即報(bào)錯(cuò),但這并不意味著這段代碼是正確的。
下面第一種情況刪除非末尾元素時(shí),VS的報(bào)錯(cuò)沒有意義,但在第二種情況下,VS的報(bào)錯(cuò)就非常有意義了。?
為了避免這種問題,你應(yīng)該在刪除元素后,不再使用已經(jīng)失效的迭代器。如果你需要在刪除元素后繼續(xù)訪問?vector
,你應(yīng)該在刪除元素后重新獲取迭代器的值。例如,vector::erase
?函數(shù)會(huì)返回一個(gè)指向被刪除元素之后的元素的迭代器,你可以使用這個(gè)返回值來更新?pos
?。
正確版本:?
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator start = pos + 1;
while (start != _finish)
{
*(start - 1) = *start;
++start;
}
--_finish;
return pos;
}
我們來測試一下刪除偶數(shù):
void test5()
{
byte::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//要求刪除所有偶數(shù)
byte::vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it=v1.erase(it);
}
else
{
++it;
}
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
?
12、帶參初始化
?一定要對(duì)_start、_finish、_out_of_storage進(jìn)行初始化,不初始化默認(rèn)隨機(jī)值。?
vector(size_t n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
這個(gè)構(gòu)造函數(shù)創(chuàng)建一個(gè)包含?n
?個(gè)元素的?vector
,每個(gè)元素都初始化為?value
。value
?參數(shù)有一個(gè)默認(rèn)值,即?T()
,它是?T
?類型的默認(rèn)構(gòu)造值。
_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
: 這一行初始化三個(gè)迭代器,它們分別指向數(shù)組的開始、當(dāng)前最后一個(gè)元素之后的位置,和分配的內(nèi)存末端。初始化為?nullptr
?表示開始時(shí)沒有分配任何內(nèi)存。reserve(n)
: 這個(gè)函數(shù)調(diào)用會(huì)分配足夠容納?n
?個(gè)元素的內(nèi)存,但不會(huì)創(chuàng)建任何元素。while (n--) { push_back(value); }
: 這個(gè)循環(huán)會(huì)不斷地添加?value
?到?vector
?中,直到添加了?n
?個(gè)元素。push_back
?函數(shù)會(huì)在?vector
?的末尾添加一個(gè)新元素,并可能會(huì)增加?vector
?的容量(如果需要)。
為什么對(duì) T& 前面要加 const ?
- 匿名對(duì)象聲明周期只在當(dāng)前一行,因?yàn)檫@行之后沒人會(huì)用它了。
- const引用會(huì)延長匿名對(duì)象的聲明周期到引用對(duì)象域結(jié)束,因?yàn)橐院笥脁x就是用匿名對(duì)象。
13、迭代器初始化
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
這個(gè)構(gòu)造函數(shù)使用兩個(gè)迭代器?first
?和?last
,它們分別指向輸入序列的開始和結(jié)束,來初始化?vector
。這個(gè)構(gòu)造函數(shù)可以用于從任何可迭代的容器(如另一個(gè)?vector
、列表、數(shù)組等)復(fù)制元素。
- 在這個(gè)構(gòu)造函數(shù)中,沒有顯式地調(diào)用?
reserve
?來預(yù)分配內(nèi)存。這意味著每次用?push_back
?時(shí),如果當(dāng)前容量不足以容納新元素,就會(huì)自動(dòng)進(jìn)行內(nèi)存重新分配。 while (first != last) { push_back(*first); ++first; }
: 這個(gè)循環(huán)會(huì)遍歷輸入序列的每個(gè)元素,從 first 開始,一直到達(dá) last(但不包括 last),并使用每個(gè)元素的值調(diào)用 push_back,將其添加到 vector 中。
?但是對(duì)于這句代碼編譯之后會(huì)報(bào)錯(cuò):
vector<int> v1(10, 5);
?這是因?yàn)檫@段代碼在vector(InputIterator first, InputIterator last)和vector(size_t n, const T& value = T())同時(shí)存在時(shí),會(huì)優(yōu)先調(diào)用前者,但調(diào)研之后在函數(shù)內(nèi)部first的模板類型為int,而*first為對(duì)int類型解引用,所以這樣報(bào)錯(cuò)了。
我們只要添加一個(gè)int類型重載函數(shù)即可解決。
vector(int n, const T& val = T())
{
reserve(n);
for (int i = 0; i < n; ++i)
{
push_back(val);
}
}
?這種情況在不加上上述函數(shù)可以正常使用,調(diào)用vector(size_t n, const T& value = T())。文章來源:http://www.zghlxwxcb.cn/news/detail-756812.html
vector<int> v1(10u, 5);
14、析構(gòu)函數(shù)
~vector()
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
15、深拷貝
vector(const vector<T>& v)
{
_start = new T[v.capacity()];
//memcoy(_start, v._start, sizeof(T) * v.size());
for (size_t i = 0; i < size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
也可以調(diào)用迭代器區(qū)間構(gòu)造tmp,再借助swap交換實(shí)現(xiàn)深拷貝。?文章來源地址http://www.zghlxwxcb.cn/news/detail-756812.html
vector(const vector<T>& v)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
16、賦值運(yùn)算符重載
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
完整版代碼&測試代碼
#pragma once
#include<assert.h>
namespace byte
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
void resize(size_t n, T val = T())
{
if (n < size())
{
_finish = _start + n;
}
else {
if (n < capacity())
reserve(n);
while (_finish != _start + n)
{
*_finish = val;
++_finish;
}
}
}
vector()
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
vector(size_t n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
vector(int n, const T& val = T())
{
reserve(n);
for (int i = 0; i < n; ++i)
{
push_back(val);
}
}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v)
{
_start = new T[v.capacity()];
//memcoy(_start, v._start, sizeof(T) * v.size());
for (size_t i = 0; i < size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
~vector()
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*size());
for (size_t i = 0; i < sz; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
++_finish;
}
void pop_back(const T& x)
{
assert(!empty());
--_finish;
}
void insert(iterator pos, const T& val)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = val;
++_finish;
}
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator start = pos + 1;
while (start != _finish)
{
*(start - 1) = *start;
++start;
}
--_finish;
return pos;
}
size_t capacity() const
{
return _end_of_storage - _start;
}
size_t size() const
{
return _finish - _start;
}
bool empty()
{
return _start == _finish;
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
private:
iterator _start;
iterator _finish;
iterator _end_of_storage;
};
void func(const vector<int>& v)
{
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << " ";
}
cout << endl;
vector<int>::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl << endl;
}
void test1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test2()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
cout << v1.size() << endl;
cout << v1.capacity() << endl;
v1.resize(10);
cout << v1.size() << endl;
cout << v1.capacity() << endl;
func(v1);
v1.resize(3);
func(v1);
}
void test3()
{
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
/*v1.insert(v1.begin(), 0);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;*/
auto pos = find(v1.begin(), v1.end(), 3);
if (pos != v1.end())
{
//v1.insert(pos, 30);
pos = v1.insert(pos, 30);
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
// insert以后我們認(rèn)為pos失效了,不能再使用
(*pos)++;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test4()
{
std::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//auto pos = find(v1.begin(), v1.end(), 2);
auto pos = find(v1.begin(), v1.end(), 4);
if (pos != v1.end())
{
v1.erase(pos);
}
(*pos)++;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test5()
{
byte::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//要求刪除所有偶數(shù)
byte::vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it=v1.erase(it);
}
else
{
++it;
}
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test6()
{
vector<int> v1(10, 5);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
vector<int> v2(v1.begin() + 1, v1.end() - 1);
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
std::string s1("hello");
vector<int> v3(s1.begin(), s1.end());
for (auto e : v3)
{
cout << e << " ";
}
cout << endl;
int a[] = { 100, 10, 2, 20, 30 };
vector<int> v4(a, a + 3);
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
v1.insert(v1.begin(), 10);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
}
到了這里,關(guān)于C++ 模擬實(shí)現(xiàn)vector的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!