经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++?vector的简单实现
来源:jb51  时间:2022/3/8 10:43:16  对本文有异议

向量

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

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

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

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

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

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

成员函数

  1. (构造函数) 构造 vector(公开成员函数)
  2. (析构函数) 析构 vector(公开成员函数)
  3. operator= 赋值给容器(公开成员函数)
  4. assign 将值赋给容器(公开成员函数)
  5. get_allocator 返回相关的分配器(公开成员函数)
  6. 元素访问
  7. at 访问指定的元素,同时进行越界检查(公开成员函数)
  8. operator[] 访问指定的元素(公开成员函数)
  9. front 访问第一个元素(公开成员函数)
  10. back 访问最后一个元素(公开成员函数)
  11. data 直接访问底层数组(公开成员函数)
  12. 迭代器
  13. begincbegin(C++11) 返回指向起始的迭代器(公开成员函数)
  14. endcend(C++11) 返回指向末尾的迭代器(公开成员函数)
  15. rbegincrbegin(C++11) 返回指向起始的逆向迭代器(公开成员函数)
  16. rendcrend(C++11) 返回指向末尾的逆向迭代器(公开成员函数)
  17. 容量
  18. empty 检查容器是否为空(公开成员函数)
  19. size 返回容纳的元素数(公开成员函数)
  20. max_size 返回可容纳的最大元素数(公开成员函数)
  21. reserve 预留存储空间(公开成员函数)
  22. capacity 返回当前存储空间能够容纳的元素数(公开成员函数)
  23. shrink_to_fit(C++11) 通过释放未使用的内存减少内存的使用(公开成员函数)
  24. 修改器
  25. clear 清除内容(公开成员函数)
  26. insert 插入元素(公开成员函数)
  27. emplace(C++11) 原位构造元素(公开成员函数)
  28. erase 擦除元素(公开成员函数)
  29. push_back 将元素添加到容器末尾(公开成员函数)
  30. emplace_back(C++11) 在容器末尾就地构造元素(公开成员函数)
  31. pop_back 移除末元素(公开成员函数)
  32. resize 改变容器中可存储元素的个数(公开成员函数)
  33. swap 交换内容(公开成员函数)
  34. 非成员函数
  35. 按照字典顺序比较 vector 中的值(函数模板)
  36. operator==
  37. operator!=(C++20 中移除)
  38. operator<(C++20 中移除)
  39. operator<=(C++20 中移除)
  40. operator>(C++20 中移除)
  41. operator>=(C++20 中移除)
  42. operator<=>(C++20)
  43. std::swap(std::vector) 特化 std::swap 算法(函数模板)
  44. erase(std::vector),erase_if(std::vector) (C++20) 擦除所有满足特定判别标准的元素(函数模板

cpp

  1. template <typename T>
  2. class Vector
  3. {
  4. public:
  5. Vector() noexcept = default;
  6. explicit Vector(size_t n) : cap_{n}, ptr_{alloc(cap_)}
  7. {
  8. for (; len_ < n; ++len_)
  9. {
  10. construct(ptr_ + len_); //调用T的默认构造
  11. }
  12. }
  13. Vector(size_t n, const T &x) : cap_{n}, ptr_{alloc(cap_)}
  14. {
  15. for (; len_ < n; ++len_)
  16. {
  17. construct(ptr_ + len_, x); //调用T的拷贝构造
  18. }
  19. }
  20. Vector(const Vector &x) : cap_{x.size()}, ptr_{alloc(cap_)} //拷贝构造
  21. {
  22. for (; len_ < x.size(); ++len_)
  23. {
  24. construct(ptr_ + len_, x[len_]);
  25. }
  26. }
  27. Vector(Vector &&x) noexcept //移动构造
  28. {
  29. cap_ = std::__exchange(x.cap_, 0);
  30. len_ = std::__exchange(x.len_, 0);
  31. ptr_ = std::__exchange(x.ptr_, nullptr);
  32. }
  33. Vector(std::initializer_list<T> li) : cap_{li.size()}, ptr_{alloc(cap_)} //初始化列表
  34. {
  35. for (auto &x : li)
  36. {
  37. construct(ptr_ + len_, x);
  38. ++len_;
  39. }
  40. }
  41.  
  42. ~Vector() noexcept
  43. {
  44. clear();
  45. dealloc(ptr_);
  46. }
  47.  
  48. void swap(Vector &x) noexcept
  49. {
  50. using std::swap; // ADL
  51. swap(cap_, x.cap_);
  52. swap(len_, x.len_);
  53. swap(ptr_, x.ptr_);
  54. }
  55. void clear() noexcept
  56. {
  57. for (; len_ > 0; --len_)
  58. {
  59. destroy(ptr_ + len_ - 1);
  60. }
  61. }
  62.  
  63. Vector &operator=(const T &x) //拷贝赋值
  64. {
  65. if (this != &x)
  66. {
  67. Vector{x}.swap(*this);
  68. }
  69. return *this;
  70. }
  71. Vector &operator=(T &&x) noexcept //移动赋值
  72. {
  73. if (this != &x)
  74. {
  75. Vector{std::move(x)}.swap(*this);
  76. }
  77. return *this;
  78. }
  79. Vector &operator=(std::initializer_list<T> li) //初始化列表赋值
  80. {
  81. Vector{li}.swap(*this);
  82. return *this;
  83. }
  84.  
  85. void push_back(const T &x) //拷贝
  86. {
  87. emplace_back(x);
  88. }
  89. void push_back(T &&x) //移动
  90. {
  91. emplace_back(x);
  92. }
  93. template <typename... Args>
  94. void emplace_back(Args &&...args) //直接传递构造函数
  95. {
  96. if (len_ == cap_)
  97. {
  98. size_t new_cap = cap_ ? cap_ * 2 : 1; //等0返回1
  99. T *new_ptr = alloc(new_cap);
  100. for (size_t new_len; new_len < len_; ++new_len)
  101. {
  102. construct(new_ptr + new_len, std::move_if_noexcept(ptr_[new_len]));
  103. }
  104. cap_ = new_cap;
  105. ptr_ = new_ptr;
  106. }
  107. construct(ptr_ + len_, std::forward<Args>(args)...);
  108. ++len_;
  109. }
  110. void pop_back() noexcept
  111. {
  112. if (len_ < cap_ / 2)
  113. {
  114. size_t new_cap = cap_ / 2;
  115. T *new_ptr = alloc(new_cap);
  116. for (size_t new_len = 0; new_len < len_; ++new_len)
  117. {
  118. construct(new_ptr + new_len, std::move_if_noexcept(ptr_[new_len]));
  119. }
  120. cap_ = new_cap;
  121. ptr_ = new_ptr;
  122. }
  123. destroy(ptr_ + len_ - 1);
  124. --len_;
  125. }
  126. size_t size() const noexcept
  127. {
  128. return len_;
  129. }
  130. size_t capacity() const noexcept
  131. {
  132. return cap_;
  133. }
  134. bool empty() const noexcept
  135. {
  136. return len_ == 0;
  137. }
  138.  
  139. T &operator[](size_t i)
  140. {
  141. return ptr_[i];
  142. }
  143. const T &operator[](size_t i) const
  144. {
  145. return ptr_[i];
  146. }
  147.  
  148. T *begin() noexcept
  149. {
  150. return ptr_;
  151. }
  152. T *end() noexcept
  153. {
  154. return ptr_ + len_;
  155. }
  156. const T *begin() const noexcept
  157. {
  158. return ptr_;
  159. }
  160. const T *end() const noexcept
  161. {
  162. return ptr_ + len_;
  163. }
  164.  
  165. private:
  166. T *alloc(size_t n) //分配n个大小内存
  167. {
  168. return static_cast<T *>(::operator new(sizeof(T) * n));
  169. }
  170. void dealloc(T *p) noexcept //释放内存
  171. {
  172. ::operator delete(p);
  173. }
  174. template <typename... Args>
  175. void construct(T *p, Args &&...args) //在这块内存上构造T类型对象
  176. {
  177. ::new (p) T(std::forward<Args>(args)...);
  178. }
  179. void destroy(T *p) noexcept
  180. {
  181. p->~T();
  182. }
  183.  
  184. private:
  185. size_t cap_{0}; //容量
  186. size_t len_{0}; //元素个数
  187. T *ptr_{nullptr};
  188. };

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注w3xue的更多内容!   

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号