C++?vector的簡單實現(xiàn)
向量
向量是序列容器,表示可以更改大小的數(shù)組。
就像數(shù)組一樣,向量對其元素使用連續(xù)的存儲位置,這意味著也可以使用指向其元素的常規(guī)指針上的偏移量來訪問其元素,并且與數(shù)組一樣高效。但與數(shù)組不同的是,它們的大小可以動態(tài)變化,它們的存儲由容器自動處理。
在內(nèi)部,向量使用動態(tài)分配的數(shù)組來存儲其元素。可能需要重新分配此數(shù)組,以便在插入新元素時增加大小,這意味著分配新數(shù)組并將所有元素移動到該數(shù)組。就處理時間而言,這是一項相對昂貴的任務(wù),因此,每次將元素添加到容器時,向量都不會重新分配。
相反,向量容器可以分配一些額外的存儲以適應(yīng)可能的增長,因此容器的實際容量可能大于嚴(yán)格需要的存儲來包含其元素(即其大?。炜梢詫崿F(xiàn)不同的增長策略,以平衡內(nèi)存使用和重新分配,但無論如何,重新分配應(yīng)僅以對數(shù)增長的大小間隔發(fā)生,以便可以在向量末尾插入單個元素,并提供攤銷的恒定時間復(fù)雜性。
因此,與數(shù)組相比,向量消耗更多的內(nèi)存,以換取管理存儲和以有效方式動態(tài)增長的能力。
與其他動態(tài)序列容器(deques、list 和 forward_lists)相比,向量非常有效地訪問其元素(就像數(shù)組一樣),并且相對有效地從其末尾添加或刪除元素。對于涉及在末尾以外的位置插入或刪除元素的操作,它們的性能比其他元素差,并且迭代器和引用的一致性低于 lists 和 forward_lists。
成員函數(shù)
(構(gòu)造函數(shù)) 構(gòu)造 vector(公開成員函數(shù)) (析構(gòu)函數(shù)) 析構(gòu) vector(公開成員函數(shù)) operator= 賦值給容器(公開成員函數(shù)) assign 將值賦給容器(公開成員函數(shù)) get_allocator 返回相關(guān)的分配器(公開成員函數(shù)) 元素訪問 at 訪問指定的元素,同時進(jìn)行越界檢查(公開成員函數(shù)) operator[] 訪問指定的元素(公開成員函數(shù)) front 訪問第一個元素(公開成員函數(shù)) back 訪問最后一個元素(公開成員函數(shù)) data 直接訪問底層數(shù)組(公開成員函數(shù)) 迭代器 begin,cbegin(C++11) 返回指向起始的迭代器(公開成員函數(shù)) end,cend(C++11) 返回指向末尾的迭代器(公開成員函數(shù)) rbegin,crbegin(C++11) 返回指向起始的逆向迭代器(公開成員函數(shù)) rend,crend(C++11) 返回指向末尾的逆向迭代器(公開成員函數(shù)) 容量 empty 檢查容器是否為空(公開成員函數(shù)) size 返回容納的元素數(shù)(公開成員函數(shù)) max_size 返回可容納的最大元素數(shù)(公開成員函數(shù)) reserve 預(yù)留存儲空間(公開成員函數(shù)) capacity 返回當(dāng)前存儲空間能夠容納的元素數(shù)(公開成員函數(shù)) shrink_to_fit(C++11) 通過釋放未使用的內(nèi)存減少內(nèi)存的使用(公開成員函數(shù)) 修改器 clear 清除內(nèi)容(公開成員函數(shù)) insert 插入元素(公開成員函數(shù)) emplace(C++11) 原位構(gòu)造元素(公開成員函數(shù)) erase 擦除元素(公開成員函數(shù)) push_back 將元素添加到容器末尾(公開成員函數(shù)) emplace_back(C++11) 在容器末尾就地構(gòu)造元素(公開成員函數(shù)) pop_back 移除末元素(公開成員函數(shù)) resize 改變?nèi)萜髦锌纱鎯υ氐膫€數(shù)(公開成員函數(shù)) swap 交換內(nèi)容(公開成員函數(shù)) 非成員函數(shù) 按照字典順序比較 vector 中的值(函數(shù)模板) operator== operator!=(C++20 中移除) operator<(C++20 中移除) operator<=(C++20 中移除) operator>(C++20 中移除) operator>=(C++20 中移除) operator<=>(C++20) std::swap(std::vector) 特化 std::swap 算法(函數(shù)模板) erase(std::vector),erase_if(std::vector) (C++20) 擦除所有滿足特定判別標(biāo)準(zhǔn)的元素(函數(shù)模板
cpp
template <typename T>
class Vector
{
public:
Vector() noexcept = default;
explicit Vector(size_t n) : cap_{n}, ptr_{alloc(cap_)}
{
for (; len_ < n; ++len_)
{
construct(ptr_ + len_); //調(diào)用T的默認(rèn)構(gòu)造
}
}
Vector(size_t n, const T &x) : cap_{n}, ptr_{alloc(cap_)}
{
for (; len_ < n; ++len_)
{
construct(ptr_ + len_, x); //調(diào)用T的拷貝構(gòu)造
}
}
Vector(const Vector &x) : cap_{x.size()}, ptr_{alloc(cap_)} //拷貝構(gòu)造
{
for (; len_ < x.size(); ++len_)
{
construct(ptr_ + len_, x[len_]);
}
}
Vector(Vector &&x) noexcept //移動構(gòu)造
{
cap_ = std::__exchange(x.cap_, 0);
len_ = std::__exchange(x.len_, 0);
ptr_ = std::__exchange(x.ptr_, nullptr);
}
Vector(std::initializer_list<T> li) : cap_{li.size()}, ptr_{alloc(cap_)} //初始化列表
{
for (auto &x : li)
{
construct(ptr_ + len_, x);
++len_;
}
}
~Vector() noexcept
{
clear();
dealloc(ptr_);
}
void swap(Vector &x) noexcept
{
using std::swap; // ADL
swap(cap_, x.cap_);
swap(len_, x.len_);
swap(ptr_, x.ptr_);
}
void clear() noexcept
{
for (; len_ > 0; --len_)
{
destroy(ptr_ + len_ - 1);
}
}
Vector &operator=(const T &x) //拷貝賦值
{
if (this != &x)
{
Vector{x}.swap(*this);
}
return *this;
}
Vector &operator=(T &&x) noexcept //移動賦值
{
if (this != &x)
{
Vector{std::move(x)}.swap(*this);
}
return *this;
}
Vector &operator=(std::initializer_list<T> li) //初始化列表賦值
{
Vector{li}.swap(*this);
return *this;
}
void push_back(const T &x) //拷貝
{
emplace_back(x);
}
void push_back(T &&x) //移動
{
emplace_back(x);
}
template <typename... Args>
void emplace_back(Args &&...args) //直接傳遞構(gòu)造函數(shù)
{
if (len_ == cap_)
{
size_t new_cap = cap_ ? cap_ * 2 : 1; //等0返回1
T *new_ptr = alloc(new_cap);
for (size_t new_len; new_len < len_; ++new_len)
{
construct(new_ptr + new_len, std::move_if_noexcept(ptr_[new_len]));
}
cap_ = new_cap;
ptr_ = new_ptr;
}
construct(ptr_ + len_, std::forward<Args>(args)...);
++len_;
}
void pop_back() noexcept
{
if (len_ < cap_ / 2)
{
size_t new_cap = cap_ / 2;
T *new_ptr = alloc(new_cap);
for (size_t new_len = 0; new_len < len_; ++new_len)
{
construct(new_ptr + new_len, std::move_if_noexcept(ptr_[new_len]));
}
cap_ = new_cap;
ptr_ = new_ptr;
}
destroy(ptr_ + len_ - 1);
--len_;
}
size_t size() const noexcept
{
return len_;
}
size_t capacity() const noexcept
{
return cap_;
}
bool empty() const noexcept
{
return len_ == 0;
}
T &operator[](size_t i)
{
return ptr_[i];
}
const T &operator[](size_t i) const
{
return ptr_[i];
}
T *begin() noexcept
{
return ptr_;
}
T *end() noexcept
{
return ptr_ + len_;
}
const T *begin() const noexcept
{
return ptr_;
}
const T *end() const noexcept
{
return ptr_ + len_;
}
private:
T *alloc(size_t n) //分配n個大小內(nèi)存
{
return static_cast<T *>(::operator new(sizeof(T) * n));
}
void dealloc(T *p) noexcept //釋放內(nèi)存
{
::operator delete(p);
}
template <typename... Args>
void construct(T *p, Args &&...args) //在這塊內(nèi)存上構(gòu)造T類型對象
{
::new (p) T(std::forward<Args>(args)...);
}
void destroy(T *p) noexcept
{
p->~T();
}
private:
size_t cap_{0}; //容量
size_t len_{0}; //元素個數(shù)
T *ptr_{nullptr};
};
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C++學(xué)習(xí)之智能指針中的unique_ptr與shared_ptr
吃獨食的unique_ptr與樂于分享的shared_ptr是C++中常見的兩個智能指針,本文主要為大家介紹了這兩個指針的使用以及智能指針使用的原因,希望對大家有所幫助2023-05-05
C語言中的long型究竟占4個字節(jié)還是8個字節(jié)(遇到的坑)
小編在復(fù)習(xí)C語言的時候踩到了不少坑,糾結(jié)long類型究竟占4個字節(jié)還是8個字節(jié)呢?好,今天通過本文給大家分享下我的詳細(xì)思路,感興趣的朋友跟隨小編一起看看吧2021-11-11
C語言經(jīng)典例程100例(經(jīng)典c程序100例)
這篇文章主要介紹了C語言經(jīng)典例程100例,經(jīng)典c程序100例,學(xué)習(xí)c語言的朋友可以參考一下2018-03-03

