底层:
动态数组/缓冲区列表,元素按照插入的顺序依次存储在内存中
特点:
1、连续存储:内部内存块连续,元素连续存放
2、动态增长:如果当前容量不足,重新申请一块更大的内存(一般为当前容量的2倍),并将元素赋值到新的内存中
3、快速随机访问:支持通过下标快速访问任何位置的元素
4、动态大小调整:大小可动态调整,可在运行时轻松添加和删除元素
5、迭代器支持:提供了迭代器用于遍历容器中元素,包括正向迭代器和反向迭代器
6、元素访问成本:通过索引访问元素的成本很低,只需要进行简单的地址计算
适合快速随机访问和动态增长
缺点:
1、插入和删除开销大:可能会导致后续元素移动,时间复杂度为o(n)
2、动态增长可能导致重新分配:容量不足时,需要重新申请内存块,导致性能开销
3、不适合频繁插入删除操作:插入和删除开销大,所以不适合
4、固定大小的元素类型:所有元素的类型必须相同,不支持存储不同类型的元素
5、指定预留空间:如果事先不能确定元素数量的上限,可能需要预留较大空间,导致资源浪费
成员方法:
1、构造函数和析构函数
2、operator= 赋值操作符重载
3、push_back() - 在末尾添加元素
4、pop_back() - 删除末尾元素
5、size() - 返回元素数量
6、capacity() - 返回容量
7、resize() - 更改大小
8、empty() - 检查是否为空
9、clear() - 清空所有元素
10、begin() - 返回指向起始位置的迭代器
11、end() - 返回指向结束位置的迭代器
12、front() - 返回第一个元素的引用
13、back() - 返回最后一个元素的引用
14、at() - 返回指定位置元素的引用,并进行越界检查
15、insert() - 在指定位置插入元素
16、erase() - 删除指定位置或范围的元素
17、swap() - 交换两个vector的内容
18、emplace() - 在指定位置构造元素
19、emplace_back() - 在末尾构造元素
类部分成员简单自定义(无迭代器):
#include<iostream>
#include <stdexcept>
template<class T>
class _Vector
{
private:
T* arr;
size_t capacity;
size_t size;
public:
//构造、析构
_Vector() : capacity(10),size(0)
{
arr = new T[capacity];
}
_Vector(size_t _size):capacity(_size),size(_size)
{
arr = new T[capacity]();
}
_Vector(const _Vector& _vector) :capacity(_vector.capacity), size(_vector.size)
{
arr = new T[capacity];
for (size_t idx = 0; idx < size; idx++) {
arr[idx] = _vector.arr[idx];
}
}
/*
移动构造:
从一个临时对象或即将销毁的对象"窃取"资源,而不是像拷贝构造函数一样创建新的资源副本,可避免不必要的资源拷贝开销,提高性能和效率
noexcept表示该构造函数不会抛出异常
*/
_Vector(_Vector&& _vector)noexcept :arr(_vector.arr),capacity(_vector.capacity), size(_vector.size)
{
_vector.arr = nullptr;
_vector.capacity = 0;
_vector.size = 0;
}
~_Vector()
{
delete[] arr;
}
T& operator[](size_t index)
{
if (index >= size)
{
throw std::out_of_range("index out of range");
}
return arr[index];
}
_Vector& operator =(const _Vector& _vector)
{
/*
防止自我赋值:
-> _vector = _vector;
1、赋值时首先会调用赋值操作符函数
2、删除当前对象中的数组arr
3、尝试拷贝自身的元素到重新分配的内存中,但由于此时arr被删除,会导致内存无法访问
-> 程序出现未定义行为,可能导致崩溃,内存泄漏等情况
*/
if (this != _vector)
{
delete[] arr;
capacity = _vector.capacity;
size = _vector.size;
arr = new T[capacity]();
for (size_t idx = 0; idx < size; idx++)
{
arr[idx] = _vector[idx];
}
}
return *this;
}
size_t getSize()const
{
return size;
}
size_t getCap()const
{
return capacity;
}
T& at(size_t index)
{
if (index >= size)
{
throw std::out_of_range("index out of range");
}
return arr[index];
}
bool isEmpty()const
{
return size == 0;
}
void clear()
{
size = 0;
}
void push_back(const T& inVal)
{
if (capacity == size)
{
reserve(capacity * 2);
}
arr[getSize()] = inVal;
}
void pop_back()
{
if (size > 0) {
size--;
}
}
void reserve(size_t _capacity)
{
if (_capacity <= capacity) {
return;
}
T* _arr = new T[_capacity];
for (size_t _size = 0; _size < size; _size++) {
_arr[_size] = arr[_size];
}
delete[] arr;
arr = _arr;
capacity = _capacity;
}
T& front()const
{
if (isEmpty()) {
throw std::out_of_range("vector is empty");
}
return arr[0];
}
T& back()const
{
if (isEmpty()) {
throw std::out_of_range("vector is empty");
}
return arr[size - 1];
}
void resize(size_t _size, T val = T())
{
if (_size < size) {
size = _size
}
else if (_size > size){
reserve(_size);
for (size_t outSize = size; outSize < _size; outSize++) {
arr[outSize] = val;
}
size = _size;
}
}
};