文章目录
基本概念
- vector数据结构和数组非常相似,也称为单端数组
- vector与普通数组区别: 不同之处在于数组是静态空间,而vector可以动态扩展
- 动态扩展: 并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间
功能
设计一个 Vector 类,该类应具备以下功能和特性:
1、基础成员函数:
- 构造函数:初始化 Vector 实例
- 析构函数:清理资源,确保无内存泄露
- 拷贝构造函数:允许通过现有的 MyVector 实例来创建一个新实例
- 拷贝赋值操作符:实现 MyVector 实例之间的赋值功能
2、核心功能:
- 添加元素到末尾:允许在 Vector 的末尾添加新元素
- 获取元素个数:返回 Vector 当前包含的元素数量
- 获取容量:返回 Vector 可以容纳的元素总数
- 访问指定索引处的元素:通过索引访问特定位置的元素
- 在指定位置插入元素:在 Vector 的特定位置插入一个新元素
- 删除数组末尾元素:移除 Vector 末尾的元素
- 清空数组:删除 Vector 中的所有元素,重置其状态
3、遍历:
- 遍历并打印数组元素:提供一个函数,通过迭代器遍历并打印出所有元素
4、高级特性:
- 容器扩容:当前容量不足以容纳更多元素时,自动扩展 Vector 的容量以存储更多元素
思路
内存分配
当容量不足以容纳新元素时,std::vector
会分配一块新的内存空间,将原有元素复制到新的内存中,然后释放原内存。这个过程确保了元素的连续存储。
动态扩容
当需要进行扩容时,std::vector
通常会将容量翻倍,以避免频繁的内存分配操作,从而减少系统开销。
涉及以下步骤:
- 分配一个更大的内存块,通常是当前大小的两倍(这个增长因子取决于实现)。
- 将当前所有元素移到新分配的内存中。
- 销毁旧元素,并释放旧内存块。
- 插入新元素。
- 在上图中, 有一个
vector<int> v
对象, 其成员变量存储在在了栈上, 包括size
,capacity
,data pointer
,分别表示数组已经使用的大小、数组的容量、数组的首地址, 最左边表示初始时刻的堆栈状态, - 某时刻调用
v.push_back(20)
, 检查发现此操作不会超出容量上限, 因此在中间的堆栈示意图中插入了20, 并更新控制结构中的size = 2
- 下一时刻调用
v.push_back(30)
, 此时检查发现此操作要求的容量不足, 因此需要重新在堆内存申请容量为4的内存空间, 如右边的示意图所示, 并且复制原来的内容到新的地址, 完成此操作后可以丢弃原来的堆内存空间, 并插入30
代码实现
vector.h
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
#include <stdexcept>
namespace mystl{
template <typename T>
class Vector
{
private:
T *elements;
size_t capacity;
size_t size;
public:
Vector():elements(nullptr), capacity(0), size(0){
};
~Vector()
{
delete[] elements;
}
Vector(const Vector& other):capacity(other.capacity),size(other.size)
{
elements = new T[capacity];
std::copy(other.elements, other.elements+size, elements);
}
Vector& operator=(const Vector& other)
{
if(this != &other)
{
delete[] elements;
capacity = other.capacity;
size = other.size;
elements = new T[capacity];
std::copy(other.elements, other.elements+size, elements);
}
return