C++模擬實現(xiàn)vector流程詳解
模擬vector
我們可以通過模板實現(xiàn)類似vector的類。我們實現(xiàn)一個StrVecTemp類,其內(nèi)部通過allocator開辟空間,存儲的類型用T來表示,T是模板類型。
template <typename T> class StrVecTemp { public: StrVecTemp() : elements(nullptr), first_free(nullptr), cap(nullptr) {} //拷貝構(gòu)造函數(shù) StrVecTemp(const StrVecTemp &); //拷貝賦值運算符 StrVecTemp &operator=(const StrVecTemp &); //移動構(gòu)造函數(shù) StrVecTemp(StrVecTemp &&src) noexcept : elements(src.elements), first_free(src.first_free), cap(src.cap) { //將源數(shù)據(jù)置空 src.elements = src.first_free = src.cap = nullptr; } template <class... Args> void emplace_back(Args &&...args); //析構(gòu)函數(shù) ~StrVecTemp(); //拷貝元素 void push_back(const T &); //拋出元素 void pop_back(T &s); //返回元素個數(shù) size_t size() const { return first_free - elements; } //返回capacity返回容量 size_t capacity() const { return cap - elements; } //返回首元素的指針 T *begin() const { return elements; } //返回第一個空閑元素指針 T *end() const { return first_free; } private: //判斷容量不足靠皮新空間 void chk_n_alloc() { if (size() == capacity()) { reallocate(); } } //重新開辟空間 void reallocate(); // copy指定范圍的元素到新的內(nèi)存中 std::pair<T *, T *> alloc_n_copy(const T *, const T *); //釋放空間 void free(); //數(shù)組首元素的指針 T *elements; //指向數(shù)組第一個空閑元素的指針 T *first_free; //指向數(shù)組尾后位置的指針 T *cap; //初始化alloc用來分配空間 static std::allocator<T> alloc; }; template <typename T> std::allocator<T> StrVecTemp<T>::alloc;
alloc在使用前要在類外初始化,因為是模板類,所以放在.h中初始化即可。
接下來我們要實現(xiàn)根據(jù)迭代器開始和結(jié)束的區(qū)間copy舊元素到新的空間里
//實現(xiàn)區(qū)間copy template <typename T> std::pair<T *, T *> StrVecTemp<T>::alloc_n_copy(const T *b, const T *e) { auto newdata = alloc.allocate(e - b); //用舊的數(shù)據(jù)初始化新的空間 auto first_free = uninitialized_copy(b, e, newdata); return {newdata, first_free}; }
實現(xiàn)copy構(gòu)造
//實現(xiàn)拷貝構(gòu)造函數(shù) template <class T> StrVecTemp<T>::StrVecTemp(const StrVecTemp &strVec) { auto rsp = alloc_n_copy(strVec.begin(), strVec.end()); //利用pair類型更新elements, cap, first_free elements = rsp.first; first_free = rsp.second; cap = rsp.second; }
實現(xiàn)copy賦值
//拷貝賦值運算符 template <class T> StrVecTemp<T> &StrVecTemp<T>::operator=(const StrVecTemp &strVec) { if (this == &strVec) { return *this; } //如果不是自賦值,就將形參copy給自己 auto rsp = alloc_n_copy(strVec.begin(), strVec.end()); elements = rsp.first; first_free = rsp.second; cap = rsp.second; }
析構(gòu)函數(shù)要先銷毀數(shù)據(jù)再回收內(nèi)存
//析構(gòu)函數(shù) template <class T> StrVecTemp<T>::~StrVecTemp() { //判斷elements是否為空 if (elements == nullptr) { return; } //緩存第一個有效元素的地址 auto dest = elements; //循環(huán)析構(gòu) for (size_t i = 0; i < size(); i++) { //析構(gòu)每一個元素 alloc.destroy(dest++); } //再回收內(nèi)存 alloc.deallocate(elements, cap - elements); elements = nullptr; cap = nullptr; first_free = nullptr; }
重新開辟空間
template <class T> void StrVecTemp<T>::reallocate() { T *newdata = nullptr; //數(shù)組為空的情況 if (elements == nullptr || cap == nullptr || first_free == nullptr) { newdata = alloc.allocate(1); elements = newdata; first_free = newdata; // cap指向數(shù)組尾元素的下一個位置 cap = newdata + 1; return; } //原數(shù)據(jù)不為空,則擴充size兩倍大小 newdata = alloc.allocate(size() * 2); //新內(nèi)存空閑位置 auto dest = newdata; //就內(nèi)存的有效位置 auto src = elements; //通過移動操作將舊數(shù)據(jù)放到新內(nèi)存中 for (size_t i = 0; i != size(); ++i) { alloc.construct(dest++, std::move(*src++)); } //移動完舊數(shù)據(jù)后一定要刪除 free(); //更新數(shù)據(jù)位置 elements = newdata; first_free = dest; cap = newdata + size() * 2; }
上面的函數(shù)用到了free函數(shù),我們自己實現(xiàn)一個free
template <typename T> void StrVecTemp<T>::free() { //先判斷elements是否為空 if (elements == nullptr) { return; } auto dest = elements; //遍歷析構(gòu)每一個對象 for (size_t i = 0; i < size(); i++) { // destroy 會析構(gòu)每一個元素 alloc.destroy(dest++); } //再整體回收內(nèi)存 alloc.deallocate(elements, cap - elements); elements = nullptr; cap = nullptr; first_free = nullptr; }
壓入元素和彈出元素
//拷貝元素 template <class T> void StrVecTemp<T>::push_back(const T &t) { chk_n_alloc(); alloc.construct(first_free++, t); } //拋出元素 template <class T> void StrVecTemp<T>::pop_back(T &s) { //先判斷是否為空 if (first_free == nullptr) { return; } //判斷size為1 if (size() == 1) { s = *elements; alloc.destroy(elements); first_free = nullptr; elements = nullptr; return; } s = *(--first_free); alloc.destroy(first_free); }
接下來要實現(xiàn)emplace_back,因為emplace_back支持多種構(gòu)造函數(shù)的參數(shù),所以要用模板參數(shù)列表的方式定義該函數(shù)。
模板參數(shù)列表和形參列表都要用參數(shù)包的方式
template <class T> template <class... Args> void StrVecTemp<T>::emplace_back(Args &&...args) { chk_n_alloc(); alloc.construct(first_free++, forward<Args>(args)...); }
Args是模板參數(shù)包,args是參數(shù)列表。因為construct的參數(shù)可能為右值引用,所以要用forward將原參數(shù)列表類型原樣轉(zhuǎn)發(fā)。
// forward既擴展了模板參數(shù)包Args,又?jǐn)U展了函數(shù)參數(shù)包args // std::forward<Args>(args)... 等價于std::forward<Ti>(ti) //比如傳遞給emplace_back(10,'c'); //相當(dāng)于調(diào)用 alloc.construct(first_free++, forward<int>(10), forward<char>('c')) //調(diào)用的就是插入cccccccccc
總結(jié)
本文模擬實現(xiàn)了vector的功能。
到此這篇關(guān)于C++模擬實現(xiàn)vector流程詳解的文章就介紹到這了,更多相關(guān)C++ vector內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言左旋轉(zhuǎn)字符串與翻轉(zhuǎn)字符串中單詞順序的方法
這篇文章主要介紹了C語言左旋轉(zhuǎn)字符串與翻轉(zhuǎn)字符串中單詞順序的方法,給出了相關(guān)的兩道算法題目作為例子,需要的朋友可以參考下2016-02-02