- 框架和编译冷知识
- vector
- 构造,尾插,reserve、【】遍历、迭代器
- 拷贝构造、赋值重载的多种写法
- resize、迭代器区间构造
- 插入、删除
- 迭代器失效
- 结语
- Bug修正、reserve时memcpy深度的浅拷贝问题
- 看别人代码,两成核心,熟悉框架
- 写一项测试一下,头文件会在源文件里面展开,调用函数时只会向上去全局空间找 不会去命名空间找,不会去类域里面找,个头文件使用了cin,则应该将cin在它上面展开,断点调试。
vector
- 底层还是顺序表:
- 构造–>尾插 -->开n个空间reserve -->支持对象【】遍历数据------>支持迭代器遍历----->拷贝构造 -->赋值重载—>resize---->支持用迭代器区间构造---->----->任意位置的插入和删除
- 写单个函数时,思考要用到哪些成员变量,哪些成员变量要改变,又怎样的改变;和参数之间的成员变量又怎样的交互,是否可以借助第三方完成
构造,尾插,reserve、【】遍历、迭代器
迭代器,对指针的重命名;或对指针的封装
template拷贝构造、赋值重载的多种写法class vector { public: typedef T* iterator; typedef const T* const_iterator; vector() :_start(nullptr) , _finsh(nullptr) , _endofstorage(nullptr) {} private: iterator _start; iterator _finsh; iterator _endofstorage; }; -----------------------------------------个数,容量,判空------------------------------------ /计算数组元素个数 size_t size()const { return _finsh - _start; } /计算数组容量大小 size_t cap()const { return _endofstorage - _start; } /数组判空 bool empty() { return size() == 0; } -----------------------------------------push_bcak------------------------------------ void push_back(const T& x) { if (_finsh == _endofstorage) { size_t newcap = cap() == 0 ? 5 : cap() * 2; reserve(newcap); } *_finsh = x; ++_finsh; //insert(end(), x); } void reserve(size_t n) { if (n>cap()) { size_t sz = size(); /记录原finsh相对于start的距离 T* tmp = new T[n]; memcpy(tmp, _start,sizeof(T)*sz); _start = tmp; _finsh = _start + sz; _endofstorage = _start + n; } } ----------------------------------------Operator[]--------------------------------- T& operator[](size_t n) { assert(n < size()); return *(_start + n); } const T& operator[](size_t n)const { assert(n < size); return *(_start + n); } iterator begin() {return _start;} const_iterator begin()const { return _start; } iterator end() { return _finsh; } const_iterator end()const { return _finsh; }
------------------------------------------------------/v1(v2)-------------------------- vector(const vectorresize、迭代器区间构造& type) { /v1开一个和v2一样大空间 _start = new T[type.cap()]; /把v2空间的数据拷贝给v1 memcpy(_start, type._start, sizeof(T) * type.size()); /更新v1 关于有效数据个数的地址 _finsh = _start + type.size(); /更新V1的容量的地址 _endofstorage = _start + type.cap(); } --------------------------------------------------2.0 /v1(v2)用v2初始化v1 vector(const vector & v) :_start(nullptr) , _finsh(nullptr) , _endofstorage(nullptr) /先初始化我自己 { reserve(v.cap()); /开一个和v2一样大的空间,有空间就可以搞事情了 for (const auto& e : v) /对v2数组每个元素的引用尾插到我这个数组里 { push_back(e); } } --------------------------------------------赋值重载 = --------------------------------- /v1=v2 v2实参传给形参tp,形参是实参的一份临时拷贝,所以tp是v1的深拷贝 vector & operator=(vector tp) { swap(tp); return *this; } void swap( vector & type) { std::swap(_start, type._start); std::swap(_finsh, type._finsh); std::swap(_endofstorage, type._endofstorage); }
void resize(size_t n, const T& value = T()) /给缺省初始化
{
if (n<=size())
{
_finsh = _start + n; /反正后面的你也访问不到
}
else
{
if (n > cap())
{
reserve(n);
}
while (_finsh<_start+n)
{
*_finsh = value;
++_finsh;
}
}
}
--------------------------------------------迭代器区间构造 ------------------------------
/类模板的成员函数,可以再定义模板参数
template /模板参数
vector(Inputiterator first, Inputiterator last)
:_start(nullptr)
, _finsh(nullptr)
, _endofstorage(nullptr)
{
while (first!=last)
{
push_back(*first);
++first;
}
}
插入、删除
iterator insert(iterator pos, const T& val)
{
assert(pos >= begin() && pos <= end());
if (_finsh == _endofstorage)
{
size_t len = pos - _start; /记录pos的相对位置
size_t newcap = cap() == 0 ? 5 : cap() * 2;
reserve(newcap);
pos = begin() + len;
}
vector::iterator it = end();
while (it>=pos)
{
*it = *(it - 1);
--it;
}
*pos = val;
_finsh++;
return pos; /返回新位置的迭代器
}
--------------------------------------------删除---------------------------------
iterator earses(iterator pos)/删除一个,删除多个就是resize了
{
/返回指向删除数据的下一个数据位置
assert(pos >= begin() && pos <= end());
auto it = pos;
while (it!=_finsh)
{
*it = *(it + 1);
++it;
}
--_finsh;
return pos;
}
迭代器失效
find某个值,返回该值的迭代器,然后进行插入,如果遇到增容,则该迭代器原空间可能会被销毁,再用迭代器可能造成野指针访问,
或者原空间没有销毁,但指向空间的值改变了。
好了,这篇水文到此结束,感谢大家的阅读点赞收藏,我们下篇文章再见!有点小迷,但说不出来哪里米,可能处处迷…
void reserve(size_t n)
{
if (n>cap())
{
size_t sz = size(); /记录原finsh相对于start的距离
T* tmp = new T[n];
if(_start)
{
memcpy(tmp, _start,sizeof(T)*sz);
delete{} _start;
/假设这里T是string 对象 ,清理时,则会先调用string对象的析构,再释放_start
}
_start = tmp;
_finsh = _start + sz;
_endofstorage = _start + n;
}
}
int main()
{
vector v1;
reserve(2);
v1.push_back("11111");
v1.push_back("11111");
v1.push_back("11111");/扩容 memcpy 后释放 已经清理了string 的_str
return 0;
}/v 走到这里时,会再次调用string 的析构_str ,释放了两次
-------------修正-------------
void reserve(size_t n)
{
if (n>cap())
{
size_t sz = size(); /记录原finsh相对于start的距离
T* tmp = new T[n];
if(_start)
{
for(size_t i=0;i
tmp[i]=_start[i]
/如果是string 对象,则是调用对象的深拷贝,
delete[] _start;
}
}
_start = tmp;
_finsh = _start + sz;
_endofstorage = _start + n;
}
}



