網(wǎng)站首頁 編程語言 正文
模擬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的功能。
視頻鏈接
源碼鏈接
原文鏈接:https://blog.csdn.net/secondtonone1/article/details/125399432
相關(guān)推薦
- 2022-07-22 CSS設(shè)置元素隱藏的4種方法
- 2022-09-27 Hive中常用正則表達式的運用小結(jié)_正則表達式
- 2023-12-26 Caused by: org.apache.ibatis.binding.BindingExcept
- 2022-11-15 如何使用ASP.NET?Core?配置文件_實用技巧
- 2023-11-20 Linux/樹莓派如何限制CPU使用率?cpulimit的基本用法
- 2022-05-27 C++的STL中accumulate函數(shù)的使用方法_C 語言
- 2024-07-18 restTemplate使用總結(jié)
- 2024-03-15 Redis中RDB和AOF
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支