C++中vector的操作和简单实现

vector本质上就是使用动态分配数组来储存元素。

如果使用数组,当新元素插入时,这个数组需要被重新分配大小,为了增加存储空间。需要开辟新空间,然后将数据转移到新数组空间中。vector和数组空间分配策略不一样,vector会分配额外空间,分配空间比实际需要存储空间更大。

1.vector的构造函数

cpp 复制代码
class vector
{
 public:
    vector()//默认构造不动
		:_start(nullptr)
		, _finish(nullptr)
	{}

	vector(vector<T>& v)//拷贝构造
	{
		reserve(v.capacity());//先扩容
		for (const auto& e : v)
		{
			push_back(e);
		}
	}

	vector(iterator first, iterator last)//迭代构造
	{
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

	vector(size_t n, const T& x = T())
	{
		resize(n, x);
	}

};	

2.iterator使用

  • begin/end 获取第一个数据位置的iterator/获取最后一个数据的下一个位置的iterator
  • 获取最后一个数据元素的reverse_iterator,获取第一个数据前一个位置的reverse_iterator
cpp 复制代码
class vector
{
    public:
		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

    private:
		iterator _start;//指向第一个元素
		iterator _finish;//指向最后一个元素的后一个
		iterator _end_storage;
};

3.vector空间增长机制

  • capacity在vs下是按照1.5被扩容的,g++下是按2被扩容的。(vs是pj版本的STL,g++是SGI版本STL)
  • reverse只负责开辟空间,如果提前知道使用多少空间,就可以避免vector增容的代价缺陷问题。

reserve(size_type n)

只分配内存,不创建元素

cpp

复制代码
std::vector<int> vec;
vec.reserve(100);  // 只分配内存,size() 不变
  • 作用:预先分配至少能容纳 n 个元素的内存空间

  • size():保持不变(仍为 0)

  • capacity():增加(≥ n)

  • 元素:不创建新元素,不改变现有元素

  • 性能:避免多次重新分配,提高 push_back 效率

  • 场景:知道大致元素数量时,避免重复分配

cpp 复制代码
void reserve(size_t n)
{
	if (capacity() < n)//需要扩容
	{
		size_t oldsize = size();
		//开空间
		T* tmp = new T[n];
		if (_start)
		{
			memcpy(tmp, _start, oldsize * sizeof(T));//拷贝
			delete [] _start;
		}


		_start = tmp;
		_finish = _start + oldsize;
		_end_storage = _start + n;
	}
}

resize(size_type n)

改变容器大小,创建/销毁元素

cpp

复制代码
std::vector<int> vec;
vec.resize(100);  // 创建100个元素,size变为100
  • 作用:改变 vector 的大小,使其包含 n 个元素

  • size():变为 n

  • capacity():可能增加(如果 n > capacity)

  • 元素

    • 如果 n > 当前 size:添加新元素(默认构造或指定值)

    • 如果 n < 当前 size:删除尾部元素

  • 场景:需要立即使用索引访问元素时

cpp 复制代码
	//如果 n 大于当前容器大小,则通过在末尾插入足够多的元素来扩展内容,达到 n 的大小。
	void resize(size_t n, const T& x = T())//默认构造
	{
		size_t old = size();
		if (n > old)
		{
			reserve(n);//先扩容,再插入
			for (int i = 0; i < n - old; i++)
			{
				push_back(x);
			}
		}
		else 
		{
			_finish = _start + n;
		}
	}

4.vector增删改查

push_back尾插

如果size超过capacity,需要扩容

cpp 复制代码
		void push_back(const T& x)
		{
			if (_finish == _end_storage)//一下扩两倍
			{
				size_t newcap = capacity() > 4 ? capacity() * 2 : 4;
				reserve(newcap);
			}
			*_finish = x;
			_finish++;
		}

pop_back尾删

cpp 复制代码
		void pop_back()
		{
			assert(size() > 0);
				--_finish;
		}

insert插入

要小心扩容之后的pos不是本对象的迭代器了,需要重新计算返回

cpp 复制代码
		iterator insert(iterator pos, const T& x)//返回迭代器
		{
			//确保插入位置合法
			assert(pos >= _start && pos <= _finish);

			//如果它满了,扩容
			if (_finish == _end_storage)
			{
				size_t len = pos - _start;
				size_t newcap = size() > 4 ? 2 * size() : 4;
				reserve(newcap);
				//注意要把pos也改变了
				pos = len + _start;
			}
			

			//把pos后的元素向后移动
			iterator end = _finish-1;//_finish指向末尾元素后一个
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;

			}
			
			//插入元素
			*pos = x;
			++_finish;
			return pos;
		}

erase删除

直接把pos后的元素向前移动一位

cpp 复制代码
		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);
			iterator it = pos;
			while (it <_finish-1)
			{
				*it = *(it + 1);
				++it;

			}
			--_finish;
			return pos;
		}

operator[]

cpp 复制代码
		T& operator[](size_t pos)
		{
			assert(pos < size());
			return *(_start + pos);
		}

5.vector迭代器失效问题

迭代器实质上就是一个指针,或者是对指针做了封装,比如vetcor迭代器就是原生态指针T*。就是迭代器底层对应指针指向的空间被收回了,造成的结果就是程序奔溃。(也就是野指针)

  • 会导致存储空间变化的操作,都可能使迭代器失效,eg:resize,reserve,insert,assign,push_back(erase vs下会强制缩容也会导致迭代器失效)
  • 不应该使用erase删除后的原来迭代器
cpp 复制代码
#include <iostream>
using namespace std;
#include <vector>

int main()
{

	int a[] = { 1,2,3,4 };
	vector<int> v(a, a + sizeof(a)/sizeof(int));
	auto pos = find(v.begin(), v.end(),1);
	auto it = v.erase(pos);//pos被删除
	//cout << *pos << endl;//报错
	cout << *it << endl;
	return 0;
}
相关推荐
疯狂的喵4 小时前
C++编译期多态实现
开发语言·c++·算法
2301_765703144 小时前
C++中的协程编程
开发语言·c++·算法
m0_748708054 小时前
实时数据压缩库
开发语言·c++·算法
小魏每天都学习5 小时前
【算法——c/c++]
c语言·c++·算法
lly2024065 小时前
jQuery Mobile 表格
开发语言
智码未来学堂5 小时前
探秘 C 语言算法之枚举:解锁解题新思路
c语言·数据结构·算法
惊讶的猫5 小时前
探究StringBuilder和StringBuffer的线程安全问题
java·开发语言
m0_748233176 小时前
30秒掌握C++核心精髓
开发语言·c++
Fleshy数模6 小时前
从数据获取到突破限制:Python爬虫进阶实战全攻略
java·开发语言
Duang007_6 小时前
【LeetCodeHot100 超详细Agent启发版本】字母异位词分组 (Group Anagrams)
开发语言·javascript·人工智能·python