網站首頁 編程語言 正文
一、迭代器
定義
vector類型的迭代器就是原生態的指針,對T*進行重命名即可
typedef T* iterator;
typedef const T* const_iterator;
普通迭代器
iterator begin()
{
return start;
}
iterator end()
{
return finish;
}
const類型迭代器
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、capacity
size_t size()
{
return finish - start;
}
size_t capacity()
{
return endOfStorage - start;
}
empty
判斷fiinsh與start是否相等即可,相等則為空
size_t empty()
{
return finish == start;
}
resize
定義一個變量保存舊的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
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];
}
front
返回動態數組第一個元素
T& front()
{
return start[0];
}
const T& front()const
{
return start[0];
}
back
返回最后一個位置前一個元素
T& back()
{
return *(finish - 1);
}
const T& back()const
{
return *(finish - 1);
}
四、修改類接口
push_back
插入前先判斷空間是否已滿,空間若滿則進行擴容,擴容時,要原來的空間容量為0的情況;將value放置到末尾位置,并將finish向后移動一個單位
void push_back(const T& value)
{
if (finish == endOfStorage)
{
//因為原來的capacity可能為0,所以要+3
reserve(capacity() * 2 + 3);
}
*finish++ = value;
}
pop_back
尾刪,先判斷對象是否為空,若不為空則將finish位置前移一個單位
void pop_back()
{
if (empty())
{
return;
}
finish--;
}
insert
任意位置插入,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;
}
erase
判斷下標合法性;從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;
}
clear
清空所有元素,令finish=start即可
void clear()
{
finish = start;
}
swap
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等值,如圖:
原文鏈接:https://blog.csdn.net/qq_44631587/article/details/126374203
相關推薦
- 2022-12-25 React安裝node-sass失敗解決方案分享_React
- 2022-02-25 Oracle工具PL/SQL的基本語法_oracle
- 2022-07-09 kernel利用pt?regs劫持seq?operations的遷移過程詳解_C 語言
- 2022-08-28 IntelliJ IDEA 下debugger熱加載(Hot Swap)有時候失效解決
- 2022-05-27 從零開始學Golang的接口_Golang
- 2024-01-30 在 Jenkins 中使用 SSH Servers 配置文件上傳路徑
- 2022-04-05 less calc計算有問題
- 2022-09-02 Golang基礎教程之字符串string實例詳解_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支