C++ vector的简单实现

作者:吃米饭 时间:2023-04-09 17:13:02 

向量

向量是序列容器,表示可以更改大小的数组。

就像数组一样,向量对其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组一样高效。但与数组不同的是,它们的大小可以动态变化,它们的存储由容器自动处理。

在内部,向量使用动态分配的数组来存储其元素。可能需要重新分配此数组,以便在插入新元素时增加大小,这意味着分配新数组并将所有元素移动到该数组。就处理时间而言,这是一项相对昂贵的任务,因此,每次将元素添加到容器时,向量都不会重新分配。

相反,向量容器可以分配一些额外的存储以适应可能的增长,因此容器的实际容量可能大于严格需要的存储来包含其元素(即其大小)。库可以实现不同的增长策略,以平衡内存使用和重新分配,但无论如何,重新分配应仅以对数增长的大小间隔发生,以便可以在向量末尾插入单个元素,并提供摊销的恒定时间复杂性。

因此,与数组相比,向量消耗更多的内存,以换取管理存储和以有效方式动态增长的能力。

与其他动态序列容器(deques、list 和 forward_lists)相比,向量非常有效地访问其元素(就像数组一样),并且相对有效地从其末尾添加或删除元素。对于涉及在末尾以外的位置插入或删除元素的操作,它们的性能比其他元素差,并且迭代器和引用的一致性低于 lists 和 forward_lists。

成员函数

(构造函数)构造 vector(公开成员函数)
(析构函数)析构 vector(公开成员函数)
operator=赋值给容器(公开成员函数)
assign将值赋给容器(公开成员函数)
get_allocator返回相关的分配器(公开成员函数)

元素访问
at访问指定的元素,同时进行越界检查(公开成员函数)
operator[]访问指定的元素(公开成员函数)
front访问第一个元素(公开成员函数)
back访问最后一个元素(公开成员函数)
data直接访问底层数组(公开成员函数)

迭代器
begin,cbegin(C++11)返回指向起始的迭代器(公开成员函数)
end,cend(C++11)返回指向末尾的迭代器(公开成员函数)
rbegin,crbegin(C++11)返回指向起始的逆向迭代器(公开成员函数)
rend,crend(C++11)返回指向末尾的逆向迭代器(公开成员函数)

容量
empty检查容器是否为空(公开成员函数)
size返回容纳的元素数(公开成员函数)
max_size返回可容纳的最大元素数(公开成员函数)
reserve预留存储空间(公开成员函数)
capacity返回当前存储空间能够容纳的元素数(公开成员函数)
shrink_to_fit(C++11)通过释放未使用的内存减少内存的使用(公开成员函数)

修改器
clear清除内容(公开成员函数)
insert插入元素(公开成员函数)
emplace(C++11)原位构造元素(公开成员函数)
erase擦除元素(公开成员函数)
push_back将元素添加到容器末尾(公开成员函数)
emplace_back(C++11)在容器末尾就地构造元素(公开成员函数)
pop_back移除末元素(公开成员函数)
resize改变容器中可存储元素的个数(公开成员函数)
swap交换内容(公开成员函数)

非成员函数
按照字典顺序比较 vector 中的值(函数模板)
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 算法(函数模板)
erase(std::vector),erase_if(std::vector)  (C++20)擦除所有满足特定判别标准的元素(函数模板

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_); //调用T的默认构造
       }
   }
   Vector(size_t n, const T &x) : cap_{n}, ptr_{alloc(cap_)}
   {
       for (; len_ < n; ++len_)
       {
           construct(ptr_ + len_, x); //调用T的拷贝构造
       }
   }
   Vector(const Vector &x) : cap_{x.size()}, ptr_{alloc(cap_)} //拷贝构造
   {
       for (; len_ < x.size(); ++len_)
       {
           construct(ptr_ + len_, x[len_]);
       }
   }
   Vector(Vector &&x) noexcept //移动构造
   {
       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) //直接传递构造函数
   {
       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个大小内存
   {
       return static_cast<T *>(::operator new(sizeof(T) * n));
   }
   void dealloc(T *p) noexcept //释放内存
   {
       ::operator delete(p);
   }
   template <typename... Args>
   void construct(T *p, Args &&...args) //在这块内存上构造T类型对象
   {
       ::new (p) T(std::forward<Args>(args)...);
   }
   void destroy(T *p) noexcept
   {
       p->~T();
   }

private:
   size_t cap_{0}; //容量
   size_t len_{0}; //元素个数
   T *ptr_{nullptr};
};

来源:https://blog.csdn.net/Cdreamfly/article/details/123315354

标签:实现,C++,vector
0
投稿

猜你喜欢

  • C#值类型和引用类型的深入理解

    2021-07-13 07:45:11
  • Java线程优先级和守护线程原理解析

    2023-03-27 16:45:30
  • Android实现屏幕锁定源码详解

    2022-10-08 00:46:38
  • 函数指针的一些概念详解

    2023-11-22 09:47:18
  • Java 实现汉字转换为拼音的实例

    2022-08-28 01:10:40
  • c#编写webservice服务引用实例分享

    2023-05-11 19:28:41
  • WPF实现魔方小游戏

    2022-09-06 01:53:18
  • Android通过HTTP协议实现断点续传下载实例

    2022-12-05 23:39:05
  • Android NotificationListenerService 通知服务原理解析

    2022-03-29 05:34:29
  • 解决RestTemplate第一次请求响应速度较慢的问题

    2021-10-20 15:50:50
  • java实现简单的图书管理系统

    2022-11-25 03:30:11
  • Java selenium处理极验滑动验证码示例

    2023-12-19 19:10:09
  • tcp、udp、ip协议分析_动力节点Java学院整理

    2023-05-17 18:00:17
  • 利用Java实现简单的词法分析器实例代码

    2023-10-06 08:14:45
  • SpringBoot整合Dozer映射框架流程详解

    2023-03-08 02:23:48
  • java中的各种修饰符作用及范围

    2022-02-10 01:03:54
  • Spring bean配置单例或多例模式方式

    2023-01-18 04:03:57
  • Android视频悬浮窗口实现的示例代码

    2022-08-01 06:50:33
  • 10分钟学会VS NuGet包私有化部署

    2022-04-23 02:28:31
  • springmvc4+hibernate4分页查询功能实现

    2021-08-16 02:28:08
  • asp之家 软件编程 m.aspxhome.com