C++———— Vector

一、vector的介紹及使用

1.1 vector的介紹

1.2 vector 的使用

1.21 vector的定義

演示:?

1.22 vector iterator 的使用

?1.begin+end

主要作用:獲取第一個數據位置的迭代器和最后一個數據的下一個位置的迭代器。

演示:

2.rbegin+rend

主要作用:rbegin獲取最后一個數據位置的迭代器,rend獲取第一個數據的前一個位置的迭代器。

演示:

1.23 vector空間增長問題

演示:

?注解:capacity的代碼在g++和vs下分別運行下會發現,vs下的capacity是按1.5倍增長的,g++是按2倍增長的,由此可以到底每一次增長多少是不確定的,需要看編譯器。

reserve是負責開辟空間的,如果提前知道需要多少空間可以使用reserve統一開辟,減少vector增容的代價問題

resize在開空間時,還會初始化,影響size.

1.23 vector增刪查改

演示:??

1.24迭代器失效

迭代器的主要作用就是讓算法不用關心底層數據結構,其實本質是指針或者是對指針進行了封裝,比如:vector的迭代器就是原生態指針T*。因此迭代器失效,實際就是迭代器底層對應的指針成為了野指針

例子一:

1.會引起其底層空間改變的操作,都有可能是迭代器失效,比如:resize、reserve、 insert、assgin、push_back(由于vector本質底層是數組,地址都是連在一起的,當他需要擴容的時候一般都是,開辟新的空間,并復制需要的值,釋放原來的空間,造成如果不更新迭代器,那么迭代器指向的是原來的空間,但是這時候原空間已經被釋放了)

做法:更新迭代器

?例子二:指定位置元素的刪除操作——erase

?解釋:如上圖,這段代碼崩了,有兩個問題,第一個問題是:erase本質其實是覆蓋,將該刪除位置的數據被后面的數據給覆蓋,上面這段代碼但他判斷一個數據為偶數的時候,會移動后面的數據到要被刪除的位置,再++t會錯過,移動數據的判斷(如下圖錯過3的判斷)。

?第二個錯誤:當最后一個數據是偶數時,end()的迭代器會-1,it會++,因此錯過end()和it的判斷,二者一直相等

如果將代碼改為如下圖所示,就沒有以上兩個錯誤了?,但是仍然報錯了

這是因為vs對迭代器的失效檢測比較極端,直接認為再erase后的迭代器失效了。再g++下就沒有這么嚴格這段程序就是正確的。

正確改法:erase會返回刪除值位置的迭代器

二、vector 的模擬實現

再模擬實現之前,我們可以看一看 vector的原碼,發現string不同的是vector的三個成員函數都是迭代器,這里值得注意的是,vector的模擬實現使用的是模板,模板不接受定義和實現分離,所以我們使用一個文件vector.h來實現

1.vector的構造和析構

代碼:

vector()
{}
//v2(v1)
vector(vector<T>& v)
{reserve(v.size());for (auto& e : v){push_back(e);}
}//v2 = v1
//現代寫法
/*swap(vector<T>& v)
{std::swap(this->_star = v._star);std::swap(this->_finish = v._finish);std::swap(this->_end_of_storage = v._end_of_storage);
}
vector<T>& operator=(vector<T> v)
{swap(v);
}*/
//傳統寫法
vector<T>& operator=(vector<T> v)
{delete[]_start;_start = _finish = _end_of_storage = nullptr;reserve(v.size());for (auto e : v){push_back(e);}return *this;
}

解析:為什么vector的構造什么東西的沒有寫,那是因為我們再成員變量給了一個缺省值,作用于初始化列表,vector再構造時會走初始化列表把_start,_finish,_end_of_storage置成nullptr

?能不能不寫vector的默認構造?不能,因為拷貝構造也屬于構造,如果不寫編譯器沒有辦法生成默認構造

能不能不寫缺省?不能因為拷貝構造也屬于構造,沒有默認構造成員變量會變成隨機值

賦值有兩種寫法一種傳統一種現代,現代主要利用自定義類型的傳值會調用拷貝構造,舉個例子:

v1 = v2調用賦值時v2需要傳值v,此時調用拷貝構造把v2的值傳給v,v中存儲的值就是v2的且兩者是獨立的不涉及淺拷貝,我們把v1與v2的內容交換,v是局部變量,出來作用域就自動釋放了,這是v會把原來v1的內容給釋放,v1現在的值與v2相同

~vector()
{delete[] _start;_start = _finish = _end_of_storage = nullptr;
}

2.end和begin的迭代器

代碼:

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
iterator begin()const
{return _start;
}
iterator end()const
{return _finish;
}
3.resize?

代碼:

void reserve(size_t n)
{if (n > capacity()){size_t Oldsize = size();T* tmp = new T[n];for (size_t i = 0; i < Oldsize(); i++){tmp[i] = _start[i];}delete[] _start;_start = tmp;_finsh = _start + Oldsize;_end_of_storage = _start + n;} 
}

?問題分析:為什么不用memcpy

1.memcpy是內存的二進制格式的拷貝,將一段內存空間中的內容原封不動的拷貝到另外一段內存空間中

2.如果拷貝的是內置類型的元素,memcpy即高效又不會出錯,但如果拷貝的是自定義類型的元素,并且自定義類型的元素中涉及到資源管理時,就會出錯,因為memcpy是淺拷貝。(結論:如果對象中涉及資源管理時,千萬不能使用memcpy進行對象之間的拷貝,因為memcpy是淺拷貝,否則可能會引起內存泄漏甚至程序崩潰)

4.size capacity?
?
size_t size()
{return _finsh - _start;
}
size_t capacity()
{return _end_of_storage - start;
}
size_t size()const
{return _finsh - _start;
}
size_t capacity()const
{return _end_of_storage - start;
}
5. push_back pop_back

void push_back(const T& x)
{if (_finish == _end_of_storage){reserve(capacity == 0 ? 4 : capacity() * 2);}*_finsh = x;finsh++;
}
void pop_back()
{assert(_finsh > _start);--finsh;
}
6. []

T& operator[](size_t i)
{assert(i < size());return _start[i];
}
const T& operator[](size_t i)const
{assert(i < size());return _start[i];
}
7.insert 和erase

?代碼:

void insert(iterator pos, const T& x)
{assert(pos > _start);assert(pos < _finish);if (_finish == _end_of_storage){size_t len = pos - _start;//reserve之后迭代器失效,記錄pos的位置,方便更新reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;//更新pos}iterator end = _finish - 1;while (pos <= end){*(end + 1) = *end;end--;}*pos = x;_finish++;
}
iterator erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);iterator end = pos + 1;while (end < _finish){*(end - 1) = *end;end++;}_finish--;return pos;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73592.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73592.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73592.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STL入門

STL入門 作者&#xff1a;blue 時間&#xff1a;2024.3 文章目錄 STL入門0.概述1.pair2.set(集合)3.vector4.string字符串類型5.queue&#xff0c;deque&#xff0c;priority_queue6.list的用法 0.概述 本文討論部分常用的STL的運用 1.pair pair是將2個數據組合成一組數據…

洛谷 P10463 Interval GCD Solution

Description 給定序列 a ( a 1 , a 2 , ? , a n ) a(a_1,a_2,\cdots,a_n) a(a1?,a2?,?,an?)&#xff0c;有 m m m 個操作分兩種&#xff1a; add ? ( l , r , k ) \operatorname{add}(l,r,k) add(l,r,k)&#xff1a;對每個 i ∈ [ l , r ] i\in[l,r] i∈[l,r] 執行 …

從聲源定位(DOA)算法仿真到工程源碼實現-第八節

一、概述 本節我們記錄在respeaker core v2 開發板上部署一個完整的聲源定位(DOA)系統&#xff0c;演示可以看第一節中的視頻。整個模塊可以分為三部分&#xff0c;第一部分為控制開發板上的LED燈顯示&#xff0c;這樣可以實時的測試算法的效果&#xff1b;第二部分為從ALSA上取…

在linux部署網站

在Linux部署網站&#xff0c;需要準備一個純凈的系統 一、系統環境準備 1.設置靜態IP地址 ? 2.關閉默認防火墻 systemctl disable firewalld --now ? 3.配置SSH密鑰登錄 4.yum update -y && reboot # 更新系統內核 5.yum install -y wget curl unzip # 安裝…

Java后端API限流秘籍:高并發的防護傘與實戰指南

目錄導航 ?? ??? 為什么需要API限流??? 主流限流算法大解析????? 阿里巴巴的限流實踐?? 四大黃金定律?? 限流策略組合拳?? 限流場景實戰?? 技術實現方案?? 最佳實踐分享?? 結語與展望?? 推薦閱讀 1. ??? 為什么需要API限流? 在高并發環境中,未…

OpenGL ES 2.0與OpenGL ES 3.1的區別

如果硬件支持且需要更高質量的圖形效果&#xff0c;推薦3.1&#xff1b;如果兼容性和開發簡便更重要&#xff0c;且效果需求不高&#xff0c;2.0更合適。不過現代車載系統可能越來越多支持3.x版本&#xff0c;所以可能傾向于使用3.1&#xff0c;但具體情況還需調查目標平臺的硬…

k8s存儲介紹(五)PV與PVC

在 Kubernetes&#xff08;k8s&#xff09;中&#xff0c;持久化存儲&#xff08;Persistent Storage&#xff09;是一個非常重要的概念&#xff0c;因為 Pod 本身是無狀態的&#xff0c;重啟后會丟失數據。為了支持有狀態應用&#xff0c;Kubernetes 提供了持久化存儲的機制&a…

ORA-00600 [2662]

一、數據庫啟動報ORA-00600[2662] [oraclenode1 ora11g]$ sqlplus / as sysdbaSQL*Plus: Release 11.2.0.3.0 Production on Thu Dec 22 14:37:00 2011Copyright (c) 1982, 2011, Oracle. All rights reserved.Connected to an idle instance.SQL> startup ORACLE instanc…

WebSocket接入SSL證書

目錄 碎碎念解決方法創建 HTTPS WebSocket 服務器創建系統服務啟動服務 碎碎念 在訪問網站時&#xff0c;使用 HTTPS 非常重要。HTTPS 協議不僅可以確保數據傳輸的安全性&#xff0c;還可以防止中間人攻擊和數據篡改等安全問題。任何沒有 SSL 證書的內容都可能會被拒絕訪問。因…

c#在work線程中怎樣更新UI控件

最近筆者調試修改項目&#xff0c;碰到了c#在work線程中怎樣更新UI控件中的場景&#xff0c;簡單總結了下&#xff0c;主要有兩個方法&#xff1a; 方法1&#xff1a;通過System.Windows.Application.Current.Dispatcher.Invoke來更新UI控件 System.Windows.Application.Curre…

?數據結構每日一題day3(順序表)★★★★★

題目描述&#xff1a;順序表L的元素遞增有序排列&#xff0c;設計一個算法在插入元素x后保持該順序表仍然遞增有序排列,插入成功后返回插入元素所在位置,不成功返回-1 算法思想&#xff1a;在遞增有序的順序表中插入元素 x 并保持有序性&#xff0c;步驟如下&#xff1a; 合法…

MyBatis中mapper.xml 的sql映射規則

一、SQL 映射文件核心元素 MyBatis 映射文件的頂級元素&#xff08;按定義順序&#xff09;&#xff1a; cache&#xff1a;命名空間的緩存配置。cache-ref&#xff1a;引用其他命名空間的緩存。resultMap&#xff1a;自定義結果集映射。sql&#xff1a;可重用的 SQL 片段。i…

【計算機網絡】計算機網絡協議、接口與服務全面解析——結合生活化案例與圖文詳解

協議、接口與服務 導讀一、協議1.1 定義1.2 組成 二、接口三、服務3.1 定義3.2 服務與協議的區別3.3 分類3.3.1 面向連接服務于無連接服務3.3.2 可靠服務和不可靠服務3.3.3 有應答服務和無應答服務 結語 導讀 大家好&#xff0c;很高興又和大家見面啦&#xff01;&#xff01;…

Ubuntu服務器中Swapper如何與虛擬內存配合

在Ubuntu服務器中&#xff0c;Swapper和虛擬內存是操作系統中重要的概念&#xff0c;它們共同協作以提高系統的內存管理效率。當物理內存不足時&#xff0c;Swapper會幫助系統將不活躍的數據從內存轉移到磁盤上的交換空間(Swap)&#xff0c;以釋放內存給需要更多資源的進程。下…

SQL Server 中常見的數據類型及其詳細解釋、內存占用和適用場景

以下是 SQL Server 中常見的數據類型及其詳細解釋、內存占用和適用場景&#xff1a; 數據類型類別數據類型解釋內存占用適用場景整數類型bigint用于存儲范圍較大的整數&#xff0c;范圍是 -2^63 (-9,223,372,036,854,775,808) 到 2^63-1 (9,223,372,036,854,775,807)8 字節需要…

vue數字公式篇 Tinymce結合使用(二)

繼上一篇的數字公式 &#xff0c; 這次的功能是將公式能插入編輯器以及修改 1、Tinymce 自定義 LateX 按鈕&#xff0c;打開公式編輯器窗口 LateX.vue window.tinymce.init({...//基礎配置這里我就不寫了setup(ed) {//自定義 LateX 按鈕ed.ui.registry.addButton(LateX, {text:…

python數據增強和轉換

數據增強和轉換 固定轉換隨機轉換概率控制的轉換 固定轉換 邊緣補充像素(Pad)尺寸變換(Resize)中心截取(CenterCrop)頂角及中心截取(FiveCrop)尺灰度變換(GrayScale) 概率控制的轉換 隨機垂直翻轉(RandomVerticalFlip)隨機應用(RandomApply) # -*- coding: utf-8 -*- fro…

Ubuntu下UEFI安全啟動安裝Nvdia驅動

簡介 眾所周知&#xff0c;Ubuntu默認使用Nouveau開源驅動&#xff0c;其性能受限&#xff0c;因此我們需要安裝Nvidia專用驅動。 安裝專用驅動的一般方法非常簡單&#xff0c;只需要sudo ubuntu-drivers devices && sudo ubuntu-drivers autoinstall即可&#xff0c…

05_循環結構三目運算符

目錄 一、雙重for循環 練習 二、break關鍵字 三、continue 關鍵字 練習 四、三元運算 / 三目運算 一、雙重for循環 外層循環 循環一次&#xff0c;&#xff0c;&#xff0c;內層循環 循環一圈&#xff01;&#xff01;&#xff01; 循環里嵌套循環&#xff1a; for(var…

數據結構初階-二叉樹鏈式

目錄 1.概念與結構 2.二叉數鏈式的實現 2.1遍歷規則 2.2申請內存空間 2.3手動構建一棵二叉樹 2.4二叉樹結點的個數 2.5二叉樹葉子結點的個數 2.6二叉樹第K層結點個數 2.7二叉樹的高度 2.8二叉樹中查找值為x的結點 2.9二叉樹的銷毀 3.層序遍歷 3.1概念 3.2層序遍歷…