建设部166号令住建部网站,WordPress的IP统计插件,网络教室网站建设,wordpress 修改目录权限目录 1.vector的介绍及使用
2.vector接口说明及模拟实现
2.1vector定义
2.2vector迭代器的使用
2.3vector容量
2.4vector增删查改
3迭代器失效
4.使用memcpy拷贝
5.模拟实现 1.vector的介绍及使用
vector的文档介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数…目录 1.vector的介绍及使用
2.vector接口说明及模拟实现
2.1vector定义
2.2vector迭代器的使用
2.3vector容量
2.4vector增删查改
3迭代器失效
4.使用memcpy拷贝
5.模拟实现 1.vector的介绍及使用
vector的文档介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问和数组一样高效。但是又不像数组它的大小是可以动态改变的而且它的大小会被容器自动处理。 3. 本质讲vector使用动态分配数组来存储它的元素。当新元素插入时候这个数组需要被重新分配大小为了增加存储空间。其做法是分配一个新的数组然后将全部元素移到这个数组。就时间而言这是一个相对代价高的任务因为每当一个新的元素加入到容器的时候vector并不会每次都重新分配大小。 4. vector分配空间策略vector会分配一些额外的空间以适应可能的增长因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何重新分配都应该是对数增长的间隔大小以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。 5. 因此vector占用了更多的存储空间为了获得管理存储空间的能力并且以一种有效的方式动态增长。 6. 与其它动态序列容器相比deque, list and forward_list vector在访问元素的时候更加高效在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作效率更低。比起list和forward_list统一的迭代器和引用更好 2.vector接口说明及模拟实现 vector底层其实是使用了三个指针来实现的。
2.1vector定义 vector()
{}vector(size_t n, const T value T())
{reserve(n);for (size_t i 0; i n; i){push_back(value);}
}vector(int n, const T value T())
{reserve(n);for (size_t i 0; i n; i){push_back(value);}
}vector(const vectorT v)
{reserve(v.capacity());for (auto e : v){push_back(e);}
}templateclass Inputiterator
vector(Inputiterator first, Inputiterator last)
{while (first ! last){push_back(*first);first;}
} 2.2vector迭代器的使用 iterator begin()
{return _start;
}iterator end()
{return _finish;
}const_iterator begin() const
{return _start;
}const_iterator end() const
{return _finish;
} 2.3vector容量 1.reserve只负责开辟空间如果确定知道需要用多少空间reserve可以缓解vector增容的代价缺陷问题。 2.resize在开空间的同时还会进行初始化影响size。 size_t size() const
{return _finish - _start;
}size_t capacity() const
{return _endOfStorage - _start;
}bool empty() const
{return _start _finish;
}void reserve(size_t n)
{if (n capacity()){T* temp new T[n];size_t len size();if (_start){//memcpy(temp, _start, sizeof(T) * len);//memcpy是浅拷贝string扩容时和原_start指向的同一片空间//析构时会重复释放for (size_t i 0; i len; i){temp[i] _start[i];}delete[] _start;}_start temp;_finish _start len;_endOfStorage _start n;}
}void resize(size_t n, const T value T())
{if (n size()){reserve(n);iterator end _start n;while (_finish ! end){*_finish value;_finish;}}_finish _start n;
} 2.4vector增删查改 void push_back(const T x)
{insert(end(), x);/*if (_endOfStorage _finish){reserve(capacity() 0 ? 4 : capacity() * 2);}*_finish x;_finish;*/
}void pop_back()
{assert(empty());--_finish;
}iterator insert(iterator pos, const T x)
{assert(pos _start);assert(pos _finish);if (_endOfStorage _finish){size_t len pos - _start;reserve(capacity() 0 ? 4 : capacity() * 2);pos _start len;}iterator it _finish;while (it ! pos){*it *(it - 1);--it;}*it x;_finish;return pos 1;
}iterator erase(iterator pos)
{assert(pos _start);assert(pos _finish);iterator it pos;while (it ! _finish - 1){*it *(it 1);it;}--_finish;return pos;
}void swap(vectorint v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);
}T operator[](size_t pos)
{assert(pos size());return _start[pos];
}const T operator[](size_t pos) const
{assert(pos size());return _start[pos];
} 3迭代器失效
1.会引起其底层空间改变的操作都有可能是迭代器失效比如resize、reserve、insert、assign、push_back等。
#include iostream
using namespace std;
#include vector
int main()
{vectorint v{ 1,2,3,4,5,6 };auto it v.begin();// 将有效元素个数增加到100个多出的位置使用8填充操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间可能会引起扩容而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值可能会引起底层容量改变v.assign(100, 8);while (it ! v.end()){cout *it ;it;}cout endl;return 0;
}
出错原因以上操作都有可能会导致vector扩容也就是说vector底层原理旧空间被释放掉而在打印时it还使用的是释放之间的旧空间在对it迭代器操作时实际操作的是一块已经被释放的空间而引起代码运行时崩溃。 解决方式在以上操作完成之后如果想要继续通过迭代器操作vector中的元素只需给it重新赋值即可。 2.指定位置元素的删除操作--erase
#include iostream
using namespace std;
#include vectorint main()
{int a[] { 1, 2, 3, 4 };vectorint v(a, a sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvectorint::iterator pos find(v.begin(), v.end(), 3);// 删除pos位置的数据导致pos迭代器失效。v.erase(pos);cout *pos endl; // 此处会导致非法访问return 0;
}
erase删除pos位置元素后pos位置之后的元素会往前搬移没有导致底层空间的改变理论上讲迭代器不应该会失效但是如果pos刚好是最后一个元素删完之后pos刚好是end的位置而end位置是没有元素的那么pos就失效了。因此删除vector中任意位置上元素时vs就认为该位置迭代器失效了
using namespace std;
#include vector
int main()
{vectorint v{ 1, 2, 3, 4 };auto it v.begin();while (it ! v.end()){if (*it % 2 0)v.erase(it);it;}return 0;
}int main()
{vectorint v{ 1, 2, 3, 4 };auto it v.begin();while (it ! v.end()){if (*it % 2 0)it v.erase(it);elseit;}return 0;
}
第二个main函数才是正确的也是解决迭代器失效问题的方法erase函数会返回删除位置的下一个接受返回值就可以避免迭代器失效。 4.使用memcpy拷贝
在模拟实现reserve函数的过程中如果使用了memcpy函数会发生什么
void reserve(size_t n)
{if (n capacity()){T* temp new T[n];size_t len size();if (_start){memcpy(temp, _start, sizeof(T) * len); delete[] _start;}_start temp;_finish _start len;_endOfStorage _start n;}
} 只插入4个数据的时候没有问题。 如果再插入一个扩容就会出错。 我们会发现运行完delete之后就把原来的数据删除了。其实就是memcpy埋下的坑。 调用memcpy其实是一个浅拷贝一个字节一个字节的拷贝其实拷贝的只是指针并没有重新开辟空间。
当我们调用delete的时候就会把原来的空间释放掉把原来的空间置为随机值。
解决方法也很简单就是我们自己拷贝。
void reserve(size_t n)
{if (n capacity()){T* temp new T[n];size_t len size();if (_start){for(size_t i 0; i len; i){temp[i] _start[i];//string拷贝是深拷贝}delete[] _start;}_start temp;_finish _start len;_endOfStorage _start n;}
} 5.模拟实现
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(){}vector(size_t n, const T value T()){reserve(n);for (size_t i 0; i n; i){push_back(value);}}vector(int n, const T value T()){reserve(n);for (size_t i 0; i n; i){push_back(value);}}templateclass Inputiteratorvector(Inputiterator first, Inputiterator last){while (first ! last){push_back(*first);first;}}void swap(vectorint v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}vector(const vectorT v){reserve(v.capacity());for (auto e : v){push_back(e);}}vectorT operator(vectorT tmp){swap(tmp);return *this;}~vector(){delete[] _start;_start _finish _endOfStorage nullptr;}void reserve(size_t n){if (n capacity()){T* temp new T[n];size_t len size();if (_start){//memcpy(temp, _start, sizeof(T) * len);memcpy是浅拷贝string扩容时和原_start指向的同一片空间析构时会重复释放for (size_t i 0; i len; i){temp[i] _start[i];}delete[] _start;}_start temp;_finish _start len;_endOfStorage _start n;}}void resize(size_t n, const T value T()){if (n size()){reserve(n);iterator end _start n;while (_finish ! end){*_finish value;_finish;}}_finish _start n;}void push_back(const T x){insert(end(), x);/*if (_endOfStorage _finish){reserve(capacity() 0 ? 4 : capacity() * 2);}*_finish x;_finish;*/}void pop_back(){assert(empty());--_finish;}iterator insert(iterator pos, const T x){assert(pos _start);assert(pos _finish);if (_endOfStorage _finish){size_t len pos - _start;reserve(capacity() 0 ? 4 : capacity() * 2);pos _start len;}iterator it _finish;while (it ! pos){*it *(it - 1);--it;}*it x;_finish;return pos 1;}iterator erase(iterator pos){assert(pos _start);assert(pos _finish);iterator it pos;while (it ! _finish - 1){*it *(it 1);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 size() const{return _finish - _start;}size_t capacity() const{return _endOfStorage - _start;}bool empty() const{return _start _finish;}private:iterator _start nullptr;iterator _finish nullptr;iterator _endOfStorage nullptr;
};