【C++修行之路】STL——模拟实现vector
创始人
2024-06-02 01:26:11
0

文章目录

  • 前言
  • 模拟
    • 类框架
    • 构造和析构
    • 深拷贝与浅拷贝问题
    • []重载
    • insert和erase
    • push_pop、empty、resize
  • 结语

前言

大家好久不见,今天我们一起来模拟实现一下STL中的vector容器。

模拟

类框架

因为物理空间连续,所以我们选择直接将原生指针作为迭代器,且整个vector容器的容量(capacity)和大小(size)均是采用三个迭代器相减来表示,有关迭代器前开后闭,我在string的模拟实现中已经讲解,不理解的可以回去看看。

namespace teacher
{templateclass vector{public://原生指针作为迭代器typedef T* iterator;typedef const T* const_iterator;//容量和大小int capacity() const{return _end_of_storage - _start;}int size() const{return _finish - _start;}//迭代器iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;};
}

构造和析构

不管是构造函数还是拷贝构造,都是要把元素一个一个的赋值上去,因此先写一个push_back函数,在其他构造中调用即可。

另外c++允许在一个模板里的函数使用模板。

需要说明的是,匿名对象的生命周期只在那一行,但如果是const T& x 修饰,生命周期就会延长到x结束为止。

vector() {};
vector(size_t n, const T& val = T())
{reserve(n);for (int i = 0; i < n; i++){push_back(val);}
}
vector(int n, const T& val = T())
{reserve(n);for (int i = 0; i < n; i++){push_back(val);}
}template
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}
}vector(const vector& v)
{vector tmp(v.begin(),v.end());swap(tmp);
}~vector()
{delete[] _start;_start = _finish = _end_of_storage = nullptr;
}void push_back(const T& x)
{if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;
}

深拷贝与浅拷贝问题

当我们的vector内存有指向其他位置的指针的时候,简单的字节拷贝(值拷贝)会让两个vector指向同一个位置。这个问题非常严重,因为如果指向同一位置,意味着要析构多次,这会让我们的程序崩溃,因此我们首先来解决一下深浅拷贝的问题。

如下图所示的扩容逻辑,可以看到我们为vector的每一个元素都重新开辟了空间,这样可以避免浅拷贝的问题。

void reserve(size_t n)
{size_t sz = size();// 容量不够才进行扩容if (n > capacity()){T* tmp = new T[n];//拷贝原来的内容if (_start){for (int i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;
}

但这样写也会有一个很严重的问题,那就是 tmp[i] = _start[i] 这一步其实也是一个浅拷贝,即会出现如图所示的问题:
在这里插入图片描述
为了解决这个问题,我们需要手写一个深拷贝的 赋值重载

void swap(vector& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}vector operator=(vector v)
{ //v是临时对象,传过来完成了拷贝构造,走了push back的逻辑,因此再交换是开了新空间的。swap(v);return *this;
}

[]重载

因为我们习惯了数组的[]读取数据,并且vector的内存连续,所以我们重载一下[]

T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}const T& operator[](size_t pos) const
{assert(pos < size());return _start[pos];
}

insert和erase

逻辑与string的模拟实现基本一样,因为这里是迭代器也不用考虑npos的问题。

尽管这里都返回了迭代器,但使用这两个函数后,我都建议你不要再使用pos,认为pos已经失效!

iterator insert(iterator pos, const T& val)
{if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 20);pos = _start + len;//扩容后更新pos 防止pos失效}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;
}iterator erase()
{iterator start = pos + 1;while (start != _finish){*(start - 1) = *start;++start;}--_finish;return pos;
}

push_pop、empty、resize

这三个函数较为简单,一笔带过

bool empty()
{return _start == _finish;
}
void pop_back()
{assert(!empty());--_finish;
}
void resize(size_t n,T val = T())
{if (n < size()){_finish = _start + n;}else{if (n > capacity()){reserve(n);}while (_finish != _start + n){*_finish = val;++_finish;}}
}

结语

以上就是本篇文章全部内容了,希望对你有所收获,我们下次再见

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...