<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
vector型別的迭代器就是原生態的指標,對T*進行重新命名即可
typedef T* iterator; typedef const T* const_iterator;
iterator begin() { return start; } iterator end() { return finish; }
const型別迭代器可以存取const成員變數
const iterator cbegin()const { return start; } const iterator cend()const { return finish; }
構造空物件
在初始化列表中對三個成員變數進行初始化
vector() :start(nullptr) , finish(nullptr) , endOfStorage(nullptr) {}
n個T型別
開闢空間以後,對finish進行自增,在空間填充元素
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; } }
過載前一個建構函式,將第一個引數設定為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; } }
之所以要對這種型別的建構函式進行過載,是因為在呼叫建構函式時,如果實參傳兩個整型數位,編譯器會預設為int型別資料,進行推演之後與前面的size_t型別不匹配,則會呼叫下面的區間構造的方法,導致程式報錯,如圖:
迭代器構造
將構造方法中迭代器的型別寫成模板型別,這樣便可以接收其它型別的迭代器,如:T型別為char,Iterator迭代器為string型別,便可以從字串中擷取字元,構造vector<char>型別的物件。
//寫成函數模板,可以接受任意型別的迭代器 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是模板引數,表示可以傳任意型別的迭代器 size_t distance(Iterator first, Iterator last) { //獲取元素個數,暫時只考慮底層空間連續的情況 int count = 0; while (first != last) { first++; count++; } return count; }
拷貝建構函式的形參必須是const類物件的參照,必須使用const型別的迭代器才能存取,複用迭代器構造的方法定義一個臨時變數temp,交換temp與當前物件
//此處拷貝建構函式的形參是const型別 vector(const vector<T>& v) :start(nullptr) , finish(nullptr) , endOfStorage(nullptr) { //▲用const型別的迭代器存取const變數 vector<T> temp(v.cbegin(), v.cend()); this->swap(temp); }
形參設定為類型別物件,呼叫賦值運運算元過載函數時,形參會拷貝實參,交換當前物件與形參的值。
vector<T>& operator=(const vector<T> v) { this->swap(v); return *this; }
釋放空間,將三個迭代器賦值為空
~vector() { delete[]start; start = nullptr; finish = nullptr; endOfStorage = nullptr; }
size_t size() { return finish - start; } size_t capacity() { return endOfStorage - start; }
判斷fiinsh與start是否相等即可,相等則為空
size_t empty() { return finish == start; }
定義一個變數儲存舊的size的值‘判斷是減小還是增加size;判斷是否需要擴容,需要則呼叫reserve函數,從舊空間的結束位置開始,給新增加的空間填充元素;最後改變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的步驟:申請新空間,拷貝舊空間的元素,釋放舊的空間。
void reserve(size_t newcapacity) { size_t oldcapacity = capacity(); if (newcapacity > oldcapacity) { size_t n = size();//儲存size()的值 T* temp = new T[newcapacity]; //start不為空時才進行拷貝舊空間元素和釋放的操作 if (start) { //memcpy淺拷貝,當vector中存放的物件內部設計資源管理 // 會有記憶體漏失和野指標問題 //memcpy(temp, start, sizeof(T) * n); for (size_t i = 0; i < n; i++) { temp[i] = start[i];//呼叫賦值運運算元過載 } delete[] start; } start = temp; //▲此處不能用satart+size(),因為size方法中有finish-start,而start值已經改變 finish = start + n; endOfStorage = start + newcapacity; } }
易錯點:
判斷start的值是否為空 ,如果原來的start為空,則不需要再拷貝元素和釋放
淺拷貝問題
finish更新問題
size()的方法內部finish-start,而此時start已經發生改變,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]; }
返回動態陣列第一個元素
T& front() { return start[0]; } const T& front()const { return start[0]; }
返回最後一個位置前一個元素
T& back() { return *(finish - 1); } const T& back()const { return *(finish - 1); }
插入前先判斷空間是否已滿,空間若滿則進行擴容,擴容時,要原來的空間容量為0的情況;將value放置到末尾位置,並將finish向後移動一個單位
void push_back(const T& value) { if (finish == endOfStorage) { //因為原來的capacity可能為0,所以要+3 reserve(capacity() * 2 + 3); } *finish++ = value; }
尾刪,先判斷物件是否為空,若不為空則將finish位置前移一個單位
void pop_back() { if (empty()) { return; } finish--; }
任意位置插入,insert的返回值為新插入的第一個元素位置的迭代器;因為插入可能會進行擴容,導致start的值改變,所以先定義一個變數儲存pos與start的相對位置;判斷是否需要擴容;從插入位置開始,將所有元素向後搬移一個位置;將pos位置的值置為要插入的值;更新finish的值。
//第二個引數用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; }
判斷下標合法性;從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; }
清空所有元素,令finish=start即可
void clear() { finish = start; }
vector內建的swap函數,呼叫標準庫中的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內部有三個成員變數,start表示起始位置,finish表示有效元素的末尾位置,endOfStorage表示空間的末尾位置;通過這三個成員變數可以得到size和capacity等值,如圖:
以上就是C++模擬實現vector的範例程式碼的詳細內容,更多關於C++ vector的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45