STL中vector模擬實現

vector各個接口函數

//構造函數
vector()
vector(size_t n,const T& val=T())
vector(int n,const T& val = T())
//拷貝構造函數
vector(const vector<T>& v)
//迭代器版本的
vector(inputiterator first, inputiterator end)
//賦值運算符重載
vector<T>& operator=( vector<T> v)
//析構函數
~vector()
//容量相關的函數
void reserve(size_t n)//擴容版本
void resize(size_t n, T val = T())//擴容+初始化版本
size_t size()const//數量
size_t capacity() const容量
//插入修改容器中的數據的函數
void push_back(T x)
iterator insert(iterator pos, const T& val)
iterator erase(iterator pos)
迭代器相關的函數
iterator begin()//指向首元素
iterator end()//指向最后一個元素的下一個位置
const_iterator begin()const 
const_iterator end()const
//容器中數據訪問的[]
T& operator[](size_t pos)
const T& operator[](size_t pos)const

vector成員中相關成員變量

vector本質上就是一個動態開辟的數組,里面的成員跟以前的順序表沒啥本質區別,但是vector是用模板實現的,可以任意類型的數據。我們也可以看看源碼中vector是怎么實現的呢?
在這里插入圖片描述

分別使用了一個迭代器的指針,一個表示首元素,一個表示最后一個元素的下一個位置,還有一個就是end_of_storage表示容量。我在下面的寫的vector當中給了缺省值,避免每次寫構造函數的時候都要初始化一下。

private:
iterator _start=nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;

默認成員函數

我給了缺省值,會自動走初始化列表,因此我在這邊不要在初始化一下了。

vector()
{}

構造函數的實現
vector支持一種這樣的構造,你可以給出n個你想初始化的值,在l類與對象那么我們知道構造函數對內置類型不做處理,對自定義類型會去調用它的構造函數。但是C++11以后對內置類型也會做處理了。int x= int(); char c=char();

vector(size_t n,const T& val=T())//c++11之后支持對內置類型也會初始化
{if (size() + n > capacity()){reserve(size() + n);}while ((int)n--)//會發生隱式類型的轉化{push_back(val);}_finish += n;}

我上面還寫了一個int類型的構造這邊就不放了,主要是模板會自動匹配它的最優選擇,我們一般給vector v(10,1);會自動隱式類型轉換成int int 的類型。

拷貝構造函數

寫法思路就是_start先開辟一塊與該容器大小相等的空間,然后將該容器的數據一個一個的拷貝過來,最后改變一下_finish跟_end_of_storage

vector(const vector<T>& v)
{std::cout << "vector(const T& v)" << std::endl;_start = new T[v.capacity()];//memcpy(_start, v._start, v.size()*sizeof(T));for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish = _start + v.size();_end_of_storage = _start + v.capacity();
}

賦值運算符重載的函數

傳統寫法
思路就是開辟一個與容器大小相同的tmp空間,然后將容器中數據傳給tmp數組,思路跟拷貝構造后面一致。

//傳統寫法
vector<T>& operator=(vector<T>& v)
{if (this != &v){iterator tmp = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){tmp[i] = v._start[i];}_start = tmp;_finish = _start + v.size();_end_of_storage = _start + v.capacity();}return *this;
}

現代寫法

就是通過算法庫里面的swap交換一下倆者的指針所指向的地址

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;}

迭代器版本的構造函數
vector還支持使用一段迭代器區間進行對象的構造。因為該迭代器區間可以是其他容器的迭代器區間,也就是說該函數接收到的迭代器的類型是不確定的,所以我們這里需要將該構造函數設計為一個函數模板,在函數體內將該迭代器區間的數據一個個尾插到容器當中即可。

template<class inputiterator>
//迭代器版本默認是左閉右開的
vector(inputiterator first, inputiterator end)
{while (first != end){push_back(*first);first++;}
}

析構函數

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

容量相關的函數

size_t size() const
{return _finish - _start;
}
size_t capacity() const
{return _end_of_storage - _start;
}

reserve的實現規則就是判斷當前的是否達到最大的容積,達到就擴容,開辟一塊tmp空間,當_start不為空的時候就開始挪動數據。

void reserve(size_t n)
{if (n > capacity()){iterator tmp = new T[n];//挪動數據if (_start){size_t sz = size();//memcpy(tmp, _start, sizeof(T) * sz);//淺拷貝for (size_t i = 0; i < size(); i++){tmp[i] = _start[i];//實現深拷貝}}delete[] _start;_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}

resize函數實現的思路就是當輸入n小于當前內存的時候我們就不需要初始化,并且跟新一下_finish=_start+n,,當大于的時候就需要分倆種情況,一種是當vector為空的時候,我們就直接在頭部開始插入數據,第二種就是本來就有數據,需要尾插數據一直達到n個大小。

void resize(size_t n, T val = T())
{if (n <=size()){_finish =_start+n;}else{reserve(n);while ((int)n--){if (_start){push_back(val);}else{insert(begin(), val);}}}
}

插入修改容器中的數據的函數

尾插數據push_back,實現思路就是插入數據首先就是擴容,然后在finish后面插入數據,然后讓finish++一下。

void push_back(T x)
{if (_finish >= _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;
}

insert()的寫法,以前的寫法就是給一個下標pos的位置,然后刪除對應pos位置上的數據,而現在這個pos變成了指針,我們在使用指針插入對應數據的時候,特別容易出現迭代器失效的情況,也就是野指針的行為,為啥呢?因此我們在插入數據的時候需要擴容,我們是額外開了一個數組,然后就會將原數組釋放掉,再讓_start指向新開辟的數組,所以我們需要保存pos指針的位置。

iterator insert(iterator pos, const T& val)
{assert(pos <=_finish);size_t len = pos - _start;if (_finish >= _end_of_storage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}iterator end = _finish - 1;pos = _start + len;//跟新pos指針的位置while (end >= pos){*(end + 1) = *end;end--;}*pos = val;_finish++;return pos;
}

erase的實現,在Linux跟vs中對erase()底層實現都有區別,vs中只要刪除了該數據,該位置的值就不可訪問或者解引用修改查看,而inux環境下就寬松了很多,我們可以隨意的訪問或者修改,但是出錯了也意味著不容易判斷。

iterator erase(iterator pos)
{assert(pos >= _start && pos < _finish);iterator it = pos + 1;while (it !=_finish){*(it - 1) = *it;it++;}_finish--;return pos;}

迭代器相關的函數和數據訪問

這個很簡單直接放代碼

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_iterator begin()const 
{return _start;
}
const_iterator end()const
{return _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];
}

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

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

相關文章

DML 數據操縱語言學習筆記

一、DML 核心概念體系 1.1 語言定位與邊界 DML&#xff08;Data Manipulation Language&#xff09;作為 SQL 三大核心語言之一&#xff0c;專注于數據行級操作&#xff0c;區別于 DDL&#xff08;結構定義&#xff09;和 DCL&#xff08;權限控制&#xff09;。其核心指令包…

springboot的跨域是什么?遇到跨域問題如何解決?

在Spring Boot中&#xff0c;跨域是指當瀏覽器中的前端應用&#xff08;如運行在某個域名和端口下的前端頁面&#xff09;請求后端接口時&#xff0c;如果后端接口所在的域名、端口或協議與前端應用不一致&#xff0c;瀏覽器會阻止這種跨域請求。這是由于瀏覽器的同源策略&…

嘯叫抑制(AFS)從算法仿真到工程源碼實現-第八節-系統搭建

一、概述 系統分為錄音模塊、數據處理模塊、播音模塊。錄音模塊和播音模塊使用alsa庫進行讀寫數據。各模塊為獨立進程處理&#xff0c;模塊之間使用命名管道進行數據的傳輸。數據處理模塊我們使用基于頻域的自適應濾波去嘯叫算法。 二、工程實現 2.1 系統流程圖 2.2 錄音模塊…

HTML——什么是塊級元素,什么是內聯元素,有何區別

在 HTML 中&#xff0c;塊級元素&#xff08;Block-level element&#xff09;和內聯元素&#xff08;Inline element&#xff09;是兩種不同類型元素&#xff0c;它們在頁面布局和樣式應用方面有不同的行為和特性。 塊級元素&#xff08;Block-level element&#xff09; 塊級…

01 設計模式和設計原則

類設計原則&#xff1a; 單一職責原則&#xff08;Single Responsibility Principle&#xff0c;SRP&#xff09;&#xff1a;實現類要職責單一開閉原則&#xff08;Open Close Principle&#xff0c;OCP&#xff09;&#xff1a;對擴展開放&#xff0c;對修改關閉里氏替換原則…

【踩坑日記】springboot 打包后實現類無法找到

試過了所有改什么目錄 依賴 clean都以失敗告終 最后將實現類的文件名從Impl改成impl宣布成功 記得使用idea自帶的重構

項目-蒼穹外賣(十五) WebSocket+語音播報功能實現(來訂單+催單)

一、介紹 二、入門案例 配置類&#xff1a; package com.sky.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;/…

【Spring篇】Spring的生命周期

一、Bean 生命周期的核心階段 1. 實例化&#xff08;Instantiation&#xff09; ? 觸發時機&#xff1a;容器啟動時&#xff08;單例 Bean&#xff09;或請求時&#xff08;原型 Bean&#xff09;。 ? 實現方式&#xff1a; 通過反射&#xff08;Class.newInstance() 或構造…

Redis、Memcached應用場景對比

環境 Redis官方網站&#xff1a; Redis - The Real-time Data Platform Redis社區版本下載地址&#xff1a;Install Redis | Docs Memcached官方網站&#xff1a;memcached - a distributed memory object caching system Memcached下載地址&#xff1a;memcached - a dis…

kettle插件-mysql8數據庫插件

場景&#xff1a;群里有小伙伴反饋kettle 7.x版本不能自動連接mysql8&#xff0c;安排&#xff01;&#xff01;&#xff01; 1、將mysql8的驅動包mysql-connector-java-8.0.20.jar丟到kettle的lib目錄下&#xff0c;重啟spoon。 2、配置數據庫連接&#xff0c;提示驅動類不對…

【軟件測試】:軟件測試實戰

1. ?動化實施步驟 1.1 編寫web測試?例 1.2 ?動化測試腳本開發 common public class AutotestUtils {public static EdgeDriver driver;// 創建驅動對象public static EdgeDriver createDriver(){// 驅動對象已經創建好了 / 沒有創建if( driver null){driver new EdgeDr…

深度學習入門1 基于Python的理論與實現

torch.unsqueeze()將一維數據變為二維數據&#xff0c;torch只能處理二維數據 tensor不能反向&#xff0c;variable可以反向。variable.data.numpy()轉換為numpy 第3章 神經網絡 實現softmax函數時的注意事項&#xff1a;為防止e的指數運算造成溢出 矩陣的第 0 維是列方向,第…

解決 Pentaho Kettle 插件集成中的 NoSuchMethodError: ContextFactory.enterContext() 錯誤

解決 Pentaho Kettle 插件集成中的 NoSuchMethodError: ContextFactory.enterContext() 錯誤 在使用 Pentaho Data Integration&#xff08;也稱為 Kettle&#xff09;進行數據集成和ETL開發時&#xff0c;開發者可能會遇到各種依賴沖突和技術挑戰。本文將詳細介紹一個常見的錯…

第 五 章:優化算法_《C++性能優化指南》_notes

優化算法 第五章重難點詳解與代碼實戰編譯與測試說明第五章核心知識點整理重難點梳理 第一部分&#xff1a;多選題&#xff08;10道&#xff09;第二部分&#xff1a;設計題&#xff08;5道&#xff09;答案與詳解多選題答案&#xff1a; 設計題參考實現&#xff08;以題目2為例…

多版本PHP開發環境配置教程:WAMPServer下MySQL/Apache/MariaDB版本安裝與切換

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、版本切換指南總結 前言 由于有幾個項目分別使用到PHP7.0 和7.4以及8.0版本&#xff0c;設置mysql也會根據PHP版本使用不同的版本&#xff0c;于是開始研究…

2024年數維杯數學建模C題天然氣水合物資源量評價解題全過程論文及程序

2024年數維杯數學建模 C題 天然氣水合物資源量評價 原題再現&#xff1a; 天然氣水合物&#xff08;Natural Gas Hydrate/Gas Hydrate&#xff09;即可燃冰&#xff0c;是天然氣與水在高壓低溫條件下形成的類冰狀結晶物質&#xff0c;因其外觀像冰&#xff0c;遇火即燃&#…

階段一:Java基礎語法

目標&#xff1a;掌握Java的基本語法&#xff0c;理解變量、數據類型、運算符、控制結構等。 1. Java開發環境搭建 安裝JDK配置環境變量編寫第一個Java程序 代碼示例&#xff1a; // HelloWorld.java public class HelloWorld { // 定義類名為 HelloWorldpublic static vo…

從0到1,解鎖Ant Design X的無限可能

Ant Design X 是什么&#xff1f; 在人工智能飛速發展的當下&#xff0c;AI 驅動的界面已成為軟件開發的重要趨勢。而 Ant Design X 正是順應這一趨勢&#xff0c;于 2024 年應運而生的一款遵循 Ant Design 設計體系的 React UI 庫&#xff0c;它旨在幫助開發者輕松打造 AI 驅…

Graphpad Prism for Mac醫學繪圖

Graphpad Prism for Mac醫學繪圖 文章目錄 Graphpad Prism for Mac醫學繪圖一、介紹二、效果三、下載 一、介紹 GraphPad Prism for Mac是一款功能強大、易于使用的科學和統計分析軟件&#xff0c;適用于各種類型的數據處理和可視化需求。無論您是進行基礎研究、臨床試驗還是學…

mysqloracledb2 (uuid函數)

項目場景&#xff1a; 創建一個32位的UUID 問題描述 原因分析&#xff1a; 解決方案&#xff1a; mysql內置UUID函數 SELECT UUID(); SELECT UUID_SHORT();oracle內置UUID函數 SELECT sys_guid() FROM dual;db2&#xff0c;模擬UUID函數 SELECT TEST || substr (CONCAT…