做cpa联盟必须要有网站吗,保定网络推广公司,网站建筑设计,wordpress维护主题目录 vector介绍
vector示意图
关于vector扩容的问题
vector框架
构造函数
析构函数
vector有关空间容量函数
insert和erase
pop_back和push_back
其它构造函数
拷贝构造
迭代器区间构造 运算符重载
关于迭代器失效问题【重点】
有关insert发生迭代器失效
有关…目录 vector介绍
vector示意图
关于vector扩容的问题
vector框架
构造函数
析构函数
vector有关空间容量函数
insert和erase
pop_back和push_back
其它构造函数
拷贝构造
迭代器区间构造 运算符重载
关于迭代器失效问题【重点】
有关insert发生迭代器失效
有关erase发生迭代器失效
vector模拟实现整体代码 vector介绍 1. vector 是表示可变大小数组的序列容器就像数组一样vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对 vector 的元素进行访问和数组一样高效。但是又不像数组它的大小是可以动态改变的而且它的大小会被容器自动处理。 2. 本质讲 vector 使用动态分配数组来存储它的元素。当新元素插入时候这个数组需要被重新分配大小为了增加存储空间。其做法是分配一个新的数组然后将全部元素移到这个数组。就时间而言这是一个相对代价高的任务因为每当一个新的元素加入到容器的时候vector 并不会每次都重新分配大小。 3. vector 分配空间策略 vector 会分配一些额外的空间以适应可能的增长因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何重新分配都应该是对数增长的间隔大小以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。 4. 与其它动态序列容器相比 deque, list and forward_list vector 在访问元素的时候更加高效在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作效率更低。比起list 和 forward_list统一的迭代器和引用更好 vector示意图 上面的图片来自于《STL源码剖析》这本书从图中我们就可以看出vector实现的基本形式。vector类的成员变量是三个指针指向起始位置的 _start 指向最后一个数据的下一个位置的_finish指向容量的下一个位置的_end_of_storage。
关于vector扩容的问题
使用以下一段demo进行测试
void TestVectorExpand()
{size_t sz;vectorint v;sz v.capacity();cout making v grow:\n;for (int i 0; i 100; i){v.push_back(i);if (sz ! v.capacity()){sz v.capacity();cout capacity changed: sz \n;}}
}
在VS2022下大致为1.5倍 在gcc下2倍 vector框架
templateclass T
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start nullptr;iterator _finish nullptr;iterator _endofstorage nullptr;
};
构造函数
vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{}
析构函数
~vector()
{delete[] _start;_start _finish _endofstorage nullptr;
}
vector有关空间容量函数
size_t capacity() const
{return _endofstorage - _start;
}size_t size() const
{return _finish - _start;
}bool empty()const
{return size() 0;
}void reserve(size_t n)
{if (n capacity()){T* tmp new T[n];size_t sz size();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;_endofstorage _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;}}
}
需要注意的是关于reserve函数当数值大于当前vector的容量时需要进行拷贝使用memcpy进行拷贝时浅拷贝对于内置类型不会有问题 但是对于自定义类型就会有问题比如string 会引发扩容就会引发对旧内容进行拷贝如果使用memcpy进行拷贝会出问题
问题如下 拷贝完以后浅拷贝回来对应指针当旧对象释放后新对象指向的内容就无意义了这就是问题所在解决办法如上面reserve函数。
insert和erase
iterator insert(iterator pos, const T x)
{assert(pos _start);assert(pos _finish);if (_finish _endofstorage){size_t len pos - _start;reserve(capacity() 0 ? 4 : capacity() * 2);pos _start len;}iterator end _finish - 1;while (end pos){*(end 1) *end;--end;}*pos x;_finish;
}iterator erase(iterator pos)
{assert(pos _start);assert(pos _finish);iterator it pos 1;while (it _finish){*(it - 1) *it;it;}--_finish;return pos;
}
pop_back和push_back
void push_back(const T x)
{if (_finish _end_of_storage){reserve(capacity() 0 ? 4 : capacity() * 2);}*_finish x;_finish;
}void pop_back()
{assert(_finish _start);_finish--;
}
其它构造函数
拷贝构造
vector(int n, const T val T())
{reserve(n);for (int i 0; i n; i){push_back(val);}
}vector(const vectorT v)
{reserve(v.capacity());for (auto e : v){push_back(e);}
}
迭代器区间构造
template class InputIterator
vector(InputIterator first, InputIterator last)
{while (first ! last){push_back(*first);first;}
} 运算符重载
void swap(vectorT v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);
}vectorT operator(vectorT tmp)
{swap(tmp);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];
}
关于迭代器失效问题【重点】
vector是一个动态数组它在内存中连续存储由于vector在内存中连续存储因此当进行某些操作时迭代器可能会失效。
插入元素(可能会导致内存重新分配)在vector中插入元素可能会导致整个容器重新分配内存这种情况下所有指向容器中元素的迭代器都会失效。
删除元素从vector中删除元素会导致被删除元素之后的迭代器失效这是因为删除操作可能会移动容器中其他元素以填补被删除元素的空位然而指向被删除元素之前的迭代器仍然有效。
重新分配任何导致vector重新分配内存的操作都会使所有迭代器失效。
有关insert发生迭代器失效 迭代器失效原因 insert时迭代器失效发生在insert前sizecapacity当insert时会先扩容但是扩容后pos还是指向原来的空间的位置且已经被释放那么当再次使用pos时就会导致程序崩溃
解决办法更新pos位置迭代器使其指向扩容后对应的位置并返回pos位置迭代器。
iterator insert(iterator pos, const T x)
{assert(pos _start);assert(pos _finish);if (_finish _endofstorage){size_t len pos - _start;reserve(capacity() 0 ? 4 : capacity() * 2);pos _start len;}iterator end _finish - 1;while (end pos){*(end 1) *end;--end;}*pos x;_finish;return pos;
}
通过查阅文档也可以发现官方的做法也是返回Insert位置的迭代器 有关erase发生迭代器失效
erase函数错误写法
void erase(iterator pos)
{assert(pos _start);assert(pos _finish);iterator begin pos 1;while (begin _finish){*(begin - 1) *begin;begin;}_finish--;
}
演示代码
运行结果
出错原因
it永远不会等于finish
解决办法返回pos位置迭代器
iterator erase(iterator pos)
{assert(pos _start);assert(pos _finish);iterator it pos 1;while (it _finish){*(it - 1) *it;it;}--_finish;return pos;
}
对应示例
void test()
{vectorint v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//删除所有偶数auto it v.begin();while(it ! v.end()){if(*it % 2 0){it v.erase(*it);}else{it;}}for(auto e : v){cout e ;}
} 通过查阅文档也可以发现官方的做法也是返回erase位置的迭代器 vector模拟实现整体代码
templateclass 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(){}template class InputIteratorvector(InputIterator first, InputIterator last){while (first ! last){push_back(*first);first;}}vector(size_t n, const T val T()){reserve(n);for (size_t 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);}}vector(const vectorT v){reserve(v.capacity());for (auto e : v){push_back(e);}}void swap(vectorT v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}vectorT operator(vectorT tmp){swap(tmp);return *this;}~vector(){delete[] _start;_start _finish _endofstorage nullptr;}void reserve(size_t n){if (n capacity()){T* tmp new T[n];size_t sz size();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;_endofstorage _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 push_back(const T x){/*if (_finish _endofstorage){reserve(capacity() 0 ? 4 : capacity() * 2);}*_finish x;_finish;*/insert(end(), x);}iterator insert(iterator pos, const T x){assert(pos _start);assert(pos _finish);if (_finish _endofstorage){size_t len pos - _start;reserve(capacity() 0 ? 4 : capacity() * 2);pos _start len;}iterator end _finish - 1;while (end pos){*(end 1) *end;--end;}*pos x;_finish;return pos;}iterator erase(iterator pos){assert(pos _start);assert(pos _finish);iterator it pos 1;while (it _finish){*(it - 1) *it;it;}--_finish;return pos;}T operator[](size_t pos){assert(pos size());return _start[pos];}const T operator[](size_t pos) const{assert(pos size());return _start[pos];}size_t capacity() const{return _endofstorage - _start;}size_t size() const{return _finish - _start;}private:iterator _start nullptr;iterator _finish nullptr;iterator _endofstorage nullptr;
};