C++ vector 核心功能解析与实现
目录
整体结构概述
赋值运算符重载
下标运算符重载
内存管理函数
元素访问函数
插入和删除操作
完整代码
在C++标准库中, vector 是一个非常常用的动态数组容器,它能够自动管理内存,并且提供了丰富的操作接口。本文将通过分析一段手写 vector 的核心代码,深入理解 vector 的底层实现原理。
整体结构概述
我们实现的 vector 类模板主要包含以下几个关键部分:
1. 数据成员:用于管理动态数组的内存和元素范围。
2. 赋值运算符重载:实现对象之间的赋值操作。
3. 下标运算符重载:支持通过 [] 访问元素。
4. 内存管理函数: reserve 和 resize 用于控制动态数组的容量和大小。
5. 元素访问函数: front 和 back 用于获取容器的首元素和尾元素。
6. 插入和删除操作: push_back 、 pop_back 、 insert 和 erase 用于元素的增删。
cpptemplate <typename T>class vector {private:iterator _start; // 指向动态数组起始位置iterator _finish; // 指向最后一个有效元素的下一个位置iterator _end_of_storage; // 指向动态数组容量的末尾位置public:typesdef T* iterator;typesdef const T* const_iterator;// 以下是具体成员函数的实现};
赋值运算符重载
cppvector<T>& operator=(vector<T>& v) {swap(v);return *this;}
现代化写法
该函数实现了 vector 对象之间的赋值操作。通过调用 swap 函数交换当前对象和传入对象的内部数据( _start 、 _finish 和 _end_of_storage ),从而高效地完成赋值。 swap 函数的具体实现通常会交换两个对象的资源,而不是逐个复制元素,这样可以提高效率。
下标运算符重载
cppT& operator[](size_t pos) {assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}
这两个函数实现了通过 [] 操作符访问 vector 中的元素。第一个函数是非 const 版本,用于修改元素;第二个函数是 const 版本,用于在 const vector 对象上读取元素。通过 assert 确保访问的下标在有效范围内,防止越界访问。
内存管理函数
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 (size_t i = 0;i < sz;i++){tmp[i] = _start[i];}delete[]_start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}
reserve 函数用于确保 vector 的容量至少为 n 。如果 n 大于当前容量,会分配一块新的更大的内存,将原有的元素逐个复制到新内存中,然后释放旧内存,并更新 _start 、 _finish 和 _end_of_storage 指针。
resize 函数
cppvoid resize(size_t n, const T& val = T()) {if (n < size()) {_finish = _start + n;} else {reserve(n);while (_finish != _start + n) {*_finish = val;++_finish;}}}
resize 函数用于改变 vector 的大小。如果 n 小于当前大小,会截断 vector ;如果 n 大于当前大小,会先调用 reserve 确保有足够的容量,然后将新增位置初始化为 val 。
元素访问函数
front 函数
cppT& front() {return *_start;}const T& front() const {return *_start;}
front 函数用于获取 vector 的首元素。非 const 版本允许修改首元素, const 版本则用于在 const vector 对象上获取首元素。
back 函数
cppT& back() {return *(_finish - 1);}const T& back() const {return *(_finish - 1);}
back 函数用于获取 vector 的尾元素。同样分为非 const 和 const 版本,分别用于修改和读取尾元素。
插入和删除操作
push_back 函数
cppvoid push_back(const T& x) {insert(end(), x);}
push_back 函数在 vector 的末尾插入一个元素,它通过调用 insert 函数实现。
pop_back 函数
cppvoid pop_back() {erase(end() - 1);}
pop_back 函数删除 vector 的尾元素,通过调用 erase 函数实现。
erase 函数
cppiterator erase(iterator pos) {iterator begin = pos + 1;while (begin != _finish) {*(begin - 1) = *begin;++begin;}_finish--;return pos;}
erase 函数删除指定位置的元素。通过将该位置之后的元素逐个向前移动,覆盖要删除的元素,然后更新 _finish 指针。
insert 函数
cppiterator insert(iterator pos, const T& x) {assert(pos <= _finish);if (_finish == _end_of_storage) {size_t len = pos - _start;size_t new_cap = (capacity() == 0) ? 4 : capacity() * 2;reserve(new_cap);pos = _start + len;}iterator end = _finish - 1;while (end >= pos) {*(end + 1) = *end;end--;}*pos = x;_finish++;return pos;}
insert 函数在指定位置插入一个元素。如果当前容量已满,会先调用 reserve 扩大容量,然后将插入位置之后的元素逐个向后移动,腾出空间插入新元素,并更新 _finish 指针。
通过以上代码的实现,我们可以对 vector 的核心功能有一个更深入的理解,掌握动态数组的内存管理和元素操作的底层原理。在实际开发中,合理使用 vector 可以提高代码的效率和可读性。
完整代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<assert.h>
namespace ldg
{template<class T>class vecctor{public://原生指针typedef T* iterator;typedef const T* const_iterator;size_t size() {return _finish - _start;}size_t capacity(){return _end_of_storage - _start;}bool empty()const {return _start == _finish;}iterator begin(){return _start;}iterator cend(){return _finish;}const_iterator cbegin()const{return _start;}const_iterator cend()const{return _finish;}//构造和销毁vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}vector(size_t n,const T& val=T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);while (n--) push_back(val);}vector(int n, const T& val = T()):_start(new T[n]), _finish(_start+n), _end_of_storage(_finish){for (int i = 0;i < n;i++)_start[i] = val;}template <class Inititerator>vector(Inititerator first, Inititerator last){while (first != last){push_back(*first);first++;}}//vector(const vector<T>& v)// :_start(nullptr)// , _finish(nullptr)// , _end_of_storage(nullptr)//{// _start = new T[v.capacity()];// //memccpy(_start,v._start,sizeof(T)*v.size());// for (size_t i = 0;i < size();i++)// {// _start[i] = v._start[i];// }// _finish = _start + v.size();// _ens_of_storage = _start + v.capacity();//}vector(const vector<T>& v):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(v.capacity());for (auto e : v)push_back(e);}~vector(){if (_start) {delete[]_start;_start = _finish = _end_of_storage = nullptr;}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_ens_of_storage, v._ens_of_storage);}vector<T>& operator=(vector<T>& v){swap(v);return *this;}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 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 (size_t i = 0;i < sz;i++){tmp[i] = _start[i];}delete[]_start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}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;}}}T& front(){return *_start;}const T& front()const{return *_start;}T& back(){return *(finish-1);}const T& back()const{return *(finish - 1);}void push_back(const T& x){insert(end(), x);}void pop_back(){ease(end() - 1);}//pos位置插入x//删除pos位置,返回pos+1iterator erase(iterator pos){iterator begin = pos + 1;while (begin = _finish){*(begin - 1) = *begin;++begin;}_finish--;return pos;}iterator insert(iterator pos, const T& x){assert(pos <= finish);if (_finish == _end_of_storage){size_t len = pos-start;size_t newst = (capacity() == 0) ? 4 : capacity() * 2;reserve(newst);pos = _start + len;//防止迭代器失效}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;end--;}*pos = x;finish--;return pos;//防止迭代器失效}private:iterator _start;iterator _finish;iterator _end_of_storage;};