成员变量和迭代器
下面有vector 存储示意图:vector 是一个左闭又开的空间,_finish 不能存储有效数据。vector 的 iterator 是T 类型的指针,不要认为 iterator 就是指针,而且后面还有 list,map,set 等各种容器的迭代器,它们都不是原生指针。在这里我们 vector 写成模板,同时不能与库里面的空间产生冲突,我们需要自己定一个命名空间,具体代码看最下面的整体带代码。
reserve()函数易错点
扩容是异地扩容,需要开一块新的空间,然后把数据拷贝过去,再将原来的空间释放掉。这里注意必须开始首位指针的相对位置,异地扩容tmp赋值给_start,此时 _start和_finish 并不指向同一块空间,而 size() 却是由 _start和_finish 计算而来,由此出错。
错误代码: _finish=_start+size();
void reserve(size_t n)
{
if (n > capacity())
{
size_t len = size();
T* tmp = new T[n];
if (_start)
{
for (size_t i = 0; i < size(); i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + len;
_end_of_storage = _start + n;
}
}
假若对象是自定义类型那么还要完成深拷贝,深拷贝不能用 memcpy 拷贝,比如对象是 string,memcpy 是值拷贝只会把*string对象的指针地址拷贝给另外一个对象,导致两个string对象的_str指针指向同一块数组空间,而析构两次。因此我们需要调用string类自己的赋值运算符重载函数进行赋值
错误代码: memcpy(_start, v._start, sizeof(T)*v.size() );
迭代器区间初始化易错点
当 T 类型为 int,运行这句代码 vector v1(10, 1); 就会报下面这个错误,说明它并没有调用上面这个函数。因为第一个形参为 size_t ,第二个实例化为 int,而实参两个都为int,且第二个用迭代器区间初始化函数,两个形参相同,此时更匹配第二个函数。调用第二个函数后对 int 解引用而报错
错误代码: vector(size_t n, const T& val = T() ); 文章来源:https://www.toymoban.com/news/detail-588738.html
vector(int n, const T& val = T())
{
//参数用int而不用size_t避免当两个参数都为int时,与下面的用迭代器初始化函数冲突
resize(n, val);
}
//用迭代器区间初始化
template<class in_T>
vector(in_T first, in_T last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
迭代器失效
由上面的扩容逻辑可以知道,插入数据有时候需要扩容,而扩容是异地扩容,原来空间已经被释放了,那么指向原来空间的迭代器自然失效了。因此我们要更新迭代器,让 insert()和erase() 函数返回新的迭代器,新的迭代器和原来迭代器到 _start 的相对距离相等。虽然有时候插入迭代器并没有失效,但是考虑不同平台实现的封装和代码的可移植性,默认它就是会失效,vs库里面实现的也是默认失效,继续用直接报错文章来源地址https://www.toymoban.com/news/detail-588738.html
整体代码
#pragma once
#include <assert.h>
namespace Me
{
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;
}
//容量和size
size_t capacity() const
{
return _end_of_storage - _start;
}
size_t size() const
{
return _finish - _start;
}
//重载operator[]
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos) const
{
assert(pos < size());
return _start[pos];
}
//无参构造
vector()
{}
//深拷贝
//不用memcpy拷贝,因为对象可能是自定义类型,比如<string>,memcpy是值拷贝,
//会导致两个string对象的_str指针指向同一块数组空间
//而析构两次,因此我们需要调用赋值运算符重载函数进行拷贝
//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();
// _end_of_storage = _start + v.capacity();
//}
//现代写法
vector(const vector<T>& v)
{
reserve(v.capacity());
for (auto& e : v)
{
//会自动更新_finish指针
push_back(e);
}
}
//赋值运算符重载
vector<T>& operator=(vector<T> v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
return *this;
}
vector(int n, const T& val = T())
{
//参数用int而不用size_t避免当两个参数都为int时,与下面的用迭代器初始化函数冲突
resize(n, val);
}
//用迭代器区间初始化
template<class in_T>
vector(in_T first, in_T last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
//析构
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
//扩容和调整
void reserve(size_t n)
{
if (n > capacity())
{
//记录原来相对位置,后面_start和_finish并不指向同一块空间
size_t len = size();
T* tmp = new T[n];
if (_start)
{
for (size_t i = 0; i < size(); i++)
{
//这里和上面一样,必须深拷贝
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + len;
_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++;
}
}
}
//打印
void print()
{
for (auto e : *this)
{
cout << e << " ";
}
cout << endl;
}
//插入 迭代器使用一次后可能会失效,
//因此要返回新的迭代器,旧的默认失效处理
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _end_of_storage)
{
//扩容需要记录相对位置,以免迭代器失效
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;//更新迭代器
}
T* end = _finish;
_finish++;
while (end >= pos)
{
*end = *(end - 1);
--end;
}
*pos = x;
return pos;
}
void push_front(const T& x)
{
insert(begin(), x);
}
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
_finish++;
}
//删除
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator end = pos;
_finish--;//先-- 因为_finish不存储有效数据
while (end < _finish)
{
*end = *(end + 1);
end++;
}
return pos;
}
void pop_back()
{
--_finish;
}
void pop_front()
{
erase(begin());
}
private:
T* _start = nullptr;
T* _finish = nullptr;
T* _end_of_storage = nullptr;
};
}
到了这里,关于【C++】vector 模拟笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!