C++之vector类的代码及其逻辑详解 (下)
1. insert()
这个就是在指定位置插入一个元素,首先计算要插入的这个位置和开头之间的距离,接着判断那个_finish 有没有碰到_endofstorage 或者_endofstorage 是不是为0,如果满足条件,那就进行扩容,然后接着重新计算距离,因为我们经过扩容了,所以可能插入的位置会不准,所以要重新计算,接着我们算一个end,这个end就是最后一个元素的位置,然后通过挪动的方式留出pos的空间,接着插入对应元素再++_finish 。
void insert(iterator pos, const T& x)
{assert(pos >= _start && pos <= _finish);size_t len = pos - _start;if (_finish == _endofstorage && _endofstorage != 0){reserve(capacity() * 2);}else{reserve(4);}pos = _start + len;iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;}
2. reserve()
这个函数就是改变vector的capacity,同时并不像resize一样会添加或者减少元素。
首先保存当前元素数量 sz,然后动态分配大小为 n 的新内存 tmp。若原内存_start 非空,则通过循环调用元素的赋值运算符将原数据逐个复制到新内存中(而非直接使用 memcpy,避免浅拷贝问题),随后释放原内存。最后更新_start 指向新内存,_finish 指向原元素末尾的下一个位置,_endofstorage 指向新容量的末尾。若 n 不大于当前容量,则不执行任何操作。
简单来说就是新开一个扩容后数组然后把旧的赋值给他,接着直接把原来的vector的三个指针直接指向新的,从而完成替换实现reserve。
void reserve(size_t n)
{if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){//memcpy(tmp, _start, sizeof(T) * sz);for (int i = 0; i < sz; i++) {tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}
}
3. resize()
这个函数就是改变vector的大小,如果比原来的size小,那就改变finish的位置。
如果比原来的size大,那就吧finish向后移动,并在每一个添加的位置赋值为val。
PS:这个val之所以要设计成const T& val=T(),是因为我们并不知道这个vector里面是什么类型的,在加上这个resize在stl库里面支持只给一个n,所以我们在这里就这么设计。意思是表用它的默认构造,我们在这里不用担心int这种内置类型,因为C++支持像int a=int(1)这种语法了。
void resize(size_t n, const T& val=T())
{if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*(_finish) = val;++_finish;}}
}
4. swap()
这个的话就是交换两个vetcor里面的内容。
原理上来说的话就是通过swap两个vector里面的三个指针来实现。
void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);
}
5. capacity()
这个的话就是返回vector的capacity,因为_endofstorage和_start是指针而不是实际的大小,所以我们在这里要做减法。
size_t capacity() const
{return (_endofstorage - _start);
}
6. size()
这个的话就是返回vector的size,原因的话和上面一样。
size_t size() const
{return (_finish - _start);
}
7. operator[]
这个的话是运算符重载的[],简单来说就是可以通过下标的方式来对vector里面的内容进行访问。
同时在这里提供了普通版本和const版本。
T& operator[](size_t pos)
{ assert(pos < size());return _start[pos];
}const T& operator[](size_t pos) const
{assert(pos < size());return _start[pos];
}
8. print()
这个就是打印,通过迭代器的方式来对vector里面的内容进行打印。
void print()
{for (auto e : *this){std::cout << e << ' ';}cout << endl;
}
9. 总结
本文围绕C++中的vector容器展开了全面解析,从基础特性到具体接口操作进行了系统梳理。
首先,明确了vector的核心特性及空间结构,让读者对其底层存储有了整体认知;接着,深入讲解了vector类的关键成员与函数,包括私有成员的作用,以及构造函数(默认、拷贝、范围构造)和析构函数在对象创建与销毁时的机制;同时,详细介绍了迭代器相关的begin、end接口,以及erase、pop_back、insert等元素增删操作,reserve、resize、swap等空间与容器管理函数,还有capacity、size的获取方式;此外,还涵盖了重载的方括号运算符(用于便捷访问元素)和print方法(用于元素输出)。
通过这些内容,全面呈现了vector的使用逻辑与核心功能,帮助读者从底层原理到实际操作,完整掌握vector容器的应用。
以下是vector的完整代码:
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace struggle
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(size_t n, const T& val = T()){resize(n, val);}vector(int n, const T& val = T()){resize(n, val);}template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(const vector<T>& v){_start = new T[v.capacity()];for (size_t i = 0; i < v.size(); i++){_start[i] = v._start[i];}_finish =_start+v.size();_endofstorage = _start + v.capacity();}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}vector():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}~vector(){delete[] _start;_start = _finish = _endofstorage = 0;}void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){//memcpy(tmp, _start, sizeof(T) * sz);for (int i = 0; i < sz; i++) {tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}void push_back(const T& x){if (_finish == _endofstorage && _endofstorage != 0){reserve(capacity() * 2);}else{reserve(4);}*_finish = x;++_finish;}size_t capacity() const{return (_endofstorage - _start);}size_t size() const{return (_finish - _start);}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}void resize(size_t n, const T& val=T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*(_finish) = val;++_finish;}}}void erase(iterator pos){assert(pos >= _start && pos < _finish);iterator it = pos;while (it + 1 != _finish){*it = *(it + 1);++it;}--_finish;}void pop_back(){assert(_start != _finish);--_finish;}void insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);size_t len = pos - _start;if (_finish == _endofstorage && _endofstorage != 0){reserve(capacity() * 2);}else{reserve(4);}pos = _start + len;iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;}/*void print(const vector<int>& v){for(auto e:v){std::cout << e << ' ';}cout << endl;}*/void print(){for (auto e : *this){std::cout << e << ' ';}cout << endl;}private:iterator _start;iterator _finish;iterator _endofstorage;};
}