做笑話網站常見的推廣方式
文章目錄
- 🚀1.迭代器
- 🚀2.構造函數與析構函數
- ??2.1 默認構造函數vector()
- ??2.2 vector(int n, const T& value = T())
- ??內置類型也有構造函數
- ??2.3 賦值重載operator=
- ??2.4 通用迭代器拷貝
- ??2.5 vector(initializer_list<T> il)
- ??2.6 拷貝構造vector(const vector<T>& v)
- ??2.6 析構函數~vector()
- 🚀3.內存相關
- 🚀4.獲取
- 🚀5.修改
- ??5.1 insert插入
- ??5.2 erase刪除
- ??5.2 push_back尾插
- ??5.3 pop_back尾刪
大家好!本文會模擬一個基本的vector類,幫助我們更好的理解vector的內置函數的實現(xiàn)與規(guī)則。
先在.h文件聲明每個需要實現(xiàn)的函數,需要實現(xiàn)的成員:
namespace bit
{template<class T>class vector{public://1.迭代器// Vector的迭代器是一個原生指針typedef T* iterator;typedef const T* const_iterator;iterator begin();iterator end();const_iterator begin() const ;const_iterator end() const;// 2.構造函數與析構函數vector();vector(int n, const T& value = T());vector<T>& operator= (vector<T> v);template<class InputIterator>vector(InputIterator first, InputIterator last);vector(initializer_list<T> il);vector(const vector<T>& v);~vector();// 3.內存相關size_t size() const;size_t capacity() const;void reserve(size_t n);void resize(size_t n, const T& value = T());//4.獲取T& operator[](size_t pos);const T& operator[](size_t pos)const;//5.修改void push_back(const T& x);void pop_back();void swap(vector<T>& v);iterator insert(iterator pos, const T& x);iterator erase(Iterator pos);private:iterator _start; // 指向數據塊的開始iterator _finish; // 指向有效數據的尾iterator _endOfStorage; // 指向存儲容量的尾};
}
備注:private有三個成員變量,都是迭代器,_start 指向數據塊的開始 ,_finish指向有效數據的尾 ,_endOfStorage指向存儲容量的尾。
接下來一步一步的剖析實現(xiàn):
🚀1.迭代器
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;}
備注: begin()返回首元素的指針,end()返回尾元素下一個位置的指針,當然也要多實現(xiàn)一個const的版本,以適應const string類型。
🚀2.構造函數與析構函數
// 2.構造函數與析構函數vector();vector(int n, const T& value = T());vector<T>& operator= (vector<T> v);template<class InputIterator>vector(InputIterator first, InputIterator last);vector(initializer_list<T> il);vector(const vector<T>& v);~vector();
??2.1 默認構造函數vector()
vector() =default;
備注:vector 不需要特別的默認構造,用編譯器生成的就行,我們知道,編譯器在我們寫了其他的構造函數時是不會生成默認構造的,所以該代碼的意思是使編譯器強制生成默認構造。
??2.2 vector(int n, const T& value = T())
vector(int num, const T& temp = T())
{reserve(num);for (int i = 0; i < num; i++){push_back(temp);}
};
備注: reserve是擴容函數,push_back是尾插函數,后面會實現(xiàn)。
??內置類型也有構造函數
??關于(重要)
const T& temp = T():
在C++中,為了滿足模板的需要,為內置類型也添加了默認構造函數
什么意思呢? 就是關于內置類型也可以這樣初始化:
int i = 0;
int j(1);
int k = int();
int x = int(2);
是不是很像類的初始化的形式 ?沒錯,在C++中,內置類型可以像類一樣傳參初始化,當然就如原本的內置類型一樣,不傳參就是隨機值,傳了的那個形參就是參數的值。
這樣做有什么好處呢?我們回到本函數實現(xiàn)的代碼,如果T = int , 則:
vector(int num, const int& temp = int())
{reserve(num);for (int i = 0; i < num; i++){push_back(temp);}
};
const int& temp = int()由于int也可以用類的方式給缺省值,被賦予了一個int類型的匿名臨時對象,cosnt又為這個臨時對象賦予常性,就可以起別名,所以這樣的語法就可以通過了。
最后,const T& temp = T()的參數形式可以滿足T為自定義類型,也可以滿足內置類型
??2.3 賦值重載operator=
vector<T>& operator= (vector<T> v){swap(v);return (*this);
};
備注:swap是一個交換private內三個成員的函數,后面會實現(xiàn)。
??2.4 通用迭代器拷貝
template<class InputIterator>
vector(InputIterator first, InputIterator last){reserve(last- first);while(first != last){push_back(*first);first++;}
}
備注:
- 這里使用的是函數模板,由編譯器推斷迭代器類型,生成對應的函數。
- 該函數的意義是支持通過其他類型的迭代器來拷貝內容,例子如下:
int main()
{string s1("123456");vector<int> test1(s1.begin(), s1.end());for (auto e : test1){cout << e<<" ";}
}
輸出:49 50 51 52 53 54
這里就做到通過string的迭代器拷貝整個s1到test1
??2.5 vector(initializer_list il)
vector(initializer_list<T> il){reserve(il.size());for (auto e : il){push_back(e);}
}
備注:
- 先簡單介紹一下 initializer_list 是什么, initializer_list是一種特殊的標準庫類型,用于在函數參數或對象構造函數中初始化列表初始化的一種方式。它允許你以簡潔的方式向函數傳遞一組值,或者在對象的構造函數中初始化一組值,可以讓函數接受不定數量的參數,而在對象構造函數中使用它可以方便地初始化成員變量。
auto test = {1,2,3,4,5};
//這里編譯器推斷的類型是 initializer_list
- 借助 initializer_list 我們就可以傳入{1,2,3,4}這種形式的數組進行初始化。
int main()
{vector<int> test1 = {1,2,3,4};for (auto e : test1){cout << e<<" ";}
}
輸出:1 2 3 4
??2.6 拷貝構造vector(const vector& v)
vector(const vector<T>& temp)
{reserve(temp.capcitity());for (auto e : temp){push_back(e);}
};
備注:無。
??2.6 析構函數~vector()
~vector(){delete[] _start;_start = nullptr;_end_of_storage = nullptr;_finish = nullptr;
}
備注:只用釋放 頭迭代器_start 就行了。
🚀3.內存相關
// 3.內存相關size_t size() const{_finish - _start;}size_t capacity() const{_end_of_storage - _start;}void reserve(size_t n){if( n > capacity()){size_t len = size();iterator tmp = new iterator[n+1];if(_start){for(int i = 0 ; i < len ; i++){tmp[i] = (*this)[i];}delete[] _start;}_start = tmp;_finish = tmp+len; _endOfStorage = tmp + n ; }}void resize(size_t n, const T& value = T()){if(n <= size()){_finish = _start +n;return;}if(n > capacity()){reserve(n);}iterator it = _finish;_finish = _start +n;while(it !=_finish ){*it = value;it++;}}
備注:
- size() 返回 vector的數據個數, capacity() 返回 vector的數據個數的容量,迭代器相減(本質是指針相減)是迭代器指向位置的距離。
- reserve()修改內存,本質上是new了一段新空間,將內容拷貝到新空間,再釋放舊空間。
- 關于const T& value = T()的意思上文有講,在2.2。
🚀4.獲取
//4.獲取T& operator[](size_t pos){return *(_start + x);}const T& operator[](size_t pos)const{return *(_start + x);}
備注:該函數使vector模板可以像數組一樣訪問元素,當然也要重載一個const版本。
🚀5.修改
//5.修改iterator insert(iterator pos, const T& x);iterator erase(Iterator pos);void push_back(const T& x);void pop_back();void swap(vector<T>& v);
??5.1 insert插入
iterator insert(iterator pos, T x)
{int len = pos - _start;//記錄pos的下標位置if (size() == capcitity())//判斷擴容{size_t new_capcitity = capcitity() == 0 ? 4 : capcitity() * 2;reserve(new_capcitity);}iterator end = _finish - 1;//記錄最后一個元素pos = _start + len;//重置pos,因為擴容后pos可能會失效while (end >= pos)//從最后一個數據開始,一個一個往后搬{*(end + 1) = *end;end--;}*pos = x;_finish++;return pos; //返回pos位置的指針
};
備注:
- 關于重置pos,因為從上文的擴容函數可知,擴容的本質是開辟新空間,所以原來的pos可能不再指向新空間的pos位置了,則導致迭代器失效(迭代器指向錯誤的位置), 則需要重置。
- 同時在使用過insert函數的迭代器也是存在迭代器失效的問題,所以,建議失效后迭代器不要訪問。除非賦值更新一下這個失效的迭代器,嚴格一點的編譯器會直接報錯。
- 為了解決迭代器失效的問題,insert以返回值的形式返回重新生效的迭代器。
例子:
vector<int> test1 = {1,2,3,4};
int cnt = 2;
vector<int>::iterator pos = test1.begin()+1;
//錯誤寫法,pos會失效
while (cnt--)
{test1.insert(pos, 0);
}
//實在要用的正確寫法
while (cnt--)
{pos= test1.insert(pos, 0);
}
??5.2 erase刪除
iterator erase(iterator pos)
{if (_start){iterator head = pos;while (head < _finish){*(head) = *(head + 1);head++;}_finish--;}return pos;
};
備注:傳入erase的迭代器也不推薦再使用,不同的平臺的情況可能不同,可能會出現(xiàn)迭代器失效的問題。
??5.2 push_back尾插
void push_back(const T& x)
{insert(_finish, x);
}
備注:復用insert。
??5.3 pop_back尾刪
void pop_back()
{erase(_finish - 1);
}
備注:復用erase。
所有的代碼:
#include <assert.h>template <class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;//構造函數vector() = default;vector(const vector<T>& temp){reserve(temp.capcitity());for (auto e : temp){push_back(e);}};template <class other>vector(other begin, other end){reserve(end - begin);while (begin != end){push_back(*begin);begin++;}};vector(int num, const T& temp = T()){reserve(num);for (int i = 0; i < num; i++){push_back(temp);}};vector<T>& operator=(vector<T> v){swap(v);return (*this);};~vector(){delete[] _start;_start = nullptr;_end_of_storage = nullptr;_finish = nullptr;}vector(initializer_list<T> il){reserve(il.size());for (auto e : il){push_back(e);}}// reserve擴容void reserve(size_t n){if (n > capcitity()){size_t len = size();T* tmp = new T[n];if (_start){//不能用memcpy 要考慮深拷貝for (int i = 0; i < len; i++){tmp[i] = (*this)[i];}delete[] _start;}_start = tmp;_finish = tmp + len;_end_of_storage = tmp + n;}};//resize重設resizevoid resize(size_t n, const T& value = T()){/*for (int i = 0; i < n; i++){push_back(value);}*/if (n <= size()){_finish = _start + n;return;}//if (n > capcitity()){reserve(n);}iterator it = _finish;iterator _finish = _start + n;while (it != _finish){*it = value;++it;}}//迭代器iterator begin() {return _start;};iterator end() {return _finish;};const_iterator begin() const{return _start;};const_iterator end() const{return _finish;};//insert插入iterator insert(iterator pos, T x){int len = pos - _start;if (size() == capcitity()){size_t new_capcitity = capcitity() == 0 ? 4 : capcitity() * 2;reserve(new_capcitity);}iterator end = _finish - 1;pos = _start + len;while (end >= pos){*(end + 1) = *end;end--;}*pos = x;_finish++;return pos;};//push_back尾插void push_back(T x){insert(_finish, x);};//pop_back()尾刪void pop_back(){erase(_finish - 1);}//capcitity容量size_t capcitity() const{return _end_of_storage - _start;};//size最后元素下標size_t size() const{return _finish - _start;};//[]T& operator[](int x){assert(x >= 0);assert(x < size());return *(_start + x);};const T& operator[](size_t x)const{assert(x >= 0);assert(x < size());return *(_start + x);};//刪除iterator erase(iterator pos){if (_start){iterator head = pos;while (head < _finish){*(head) = *(head + 1);head++;}_finish--;}return pos;};//void swap(vector<T>& v){std::swap(v._start, _start);std::swap(v._finish, _finish);std::swap(v._end_of_storage, _end_of_storage);};
private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;
};
本文就到這里,感謝你看到這里!
我知道一些人看文章喜歡靜靜看,不評論,但是他會點贊,這樣的人,帥氣低調有內涵,美麗大方很優(yōu)雅,明人不說暗話,要你手上的一個點贊!