【STL】之Vector的模拟实现
2017-03-07 23:26
471 查看
一:迭代器失效?
前面我们了解迭代器其实就是智能指针,可以通过运算符的操作来实现接口函数,但有时有会存在安全隐患。这就是我们常说的迭代器失效。所谓的迭代器失效其实是找某个位置的元素,删除,然后再通过operator++,operator--访问下一个元素,会出现野指针造成崩溃的问题;如下:
#include<iostream> #include<list> using namespace std; void TestList() { list<int> l; l.push_back(1); l.push_back(2); l.push_back(3); list<int>::iterator it = l.begin(); while (it!=l.end()) { if (*it % 2 == 0) { l.erase (it); } ++it; } cout << endl; }
我们分析程序为什么会挂掉,我们知道it是一个指针,当执行erase函数时,会将当前的指针释放掉,而it又要和下一个指针链上,这样就会出现一个非法的指针指向一个合法的指针,也就是常说的野指针的问题,从而导致内存崩溃,那么怎么才能防止野指针呢?
void TestList() { list<int> l; l.push_back(1); l.push_back(2); l.push_back(3); l.push_back(4); list<int>::iterator it = l.begin(); while (it!=l.end()) { if (*it % 2 == 0) { it = l.erase (it); } else { ++it; } } cout << endl; }
我们的方法时先把当前位置的元素删除,然后返回下一个迭代器,再通过operator++,或者operator--访问下一个元素。结果显示如下:
二:resize()函数和reseve()函数的区别:
我们先看resize函数:void TestVector() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); vector<int> ::iterator it = v.begin(); while (it!=v.end()) { cout << *it << " "; ++it; } cout << endl; v.resize(2); cout << "size:" << v.size() << endl; cout << "capacity:" << v.capacity() << endl; v.resize(4); cout << "size:" << v.size() << endl; cout << "capacity:" << v.capacity() << endl; v.resize(6); cout << "size:" << v.size() << endl; cout << "capacity:" << v.capacity() << endl; }
为什么会出现这种结果?我们看看STL中是如何解释的。
在STL中resize()函数的作用是改变vector元素的个数:
主要有三层含义:
1:如果n比vector容器的size小,结果size减小到n,然后删除n之后的数据。
2:如果n比vector容器的size大,扩展空间,然后在size后面插入元素并且初始化,否则初始化为缺省值。
3:如果n比vector容器的capacity还要大,自动进行内存分配。
reseve()函数:
void TestVector() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); vector<int> ::iterator it = v.begin(); while (it!=v.end()) { cout << *it << " "; ++it; } cout << endl; v.reserve(2); cout << "size:" << v.size() << endl; cout << "capacity:" << v.capacity() << endl; v.reserve(4); cout << "size:" << v.size() << endl; cout << "capacity:" << v.capacity() << endl; v.reserve(6); cout << "size:" << v.size() << endl; cout << "capacity:" << v.capacity() << endl; }
在STL中reserve()的作用是改变容量:
1:如果n的大小比vector的容量大,开空间增容到n
2:其他的情况,没有开空间,vetor的容量不受影响。而且size的值没有变化。
当然使用reserve的优点是减少开销。
总结resize()函数时改变数组的个数并对其初始化,而reserve()函数只是改变容量。
三.STL中Vector的模拟实现
.h文件 #pragma once #include<iostream> #include<assert.h> using namespace std; template <class T> class Vector { public: typedef T* Iterator; typedef T* ConstIterator; Vector() :_start(NULL) ,_finsh(NULL) ,_EndOfStorage(NULL) {} //v1(v2) Vector(const Vector &v) :_start(NULL) , _finsh(NULL) , _EndOfStorage(NULL) { size_t size = Size(); size_t capacity = Capacity(); T*tmp = new T[capacity];//开辟空间 for (size_t i = 0; i < size; ++i)//拷贝数据 { //memcpy在string会出现浅拷贝 tmp[i] = v._start[i]; } delete[]_start; _start = tmp; _finsh = v._finsh; _EndOfStorage = v._EndOfStorage; } //v1 = v3 Vector<T>&operator = (Vector<T>&v) { swap(_start, v._start); swap(_finsh, v._finsh); swap(_EndOfStorage, v._EndOfStorage); return *this; } ~Vector() { _Destroy(); } void PushBack(const T& val) { _Expand(Capacity()*2 + 3); *_finsh = val; ++_finsh; } void PopBack() { Erase(End()); } //改变容量 void Reserve(size_t n) { assert(n > 0); if (_finsh == _EndOfStorage) { _Expand(n); } } //改变数组的个数 void Resize(size_t n, T val = T()) { if (n > Capacity()) { _Expand(n); } if (n < Size()) { //--_Size(); _finsh = _start + n; } else { for (size_t i = Size(); i < Capacity(); ++i) { _start[i] = val; } } } //随机位置的插入 void Insert(Iterator pos,size_t n, const T&x) { size_t sub = pos - strat;//当前位置与_start的相对位置 _Expand(n);//检查容量 size_t pos = _start + pos;//更新pos防止迭代器失效 Iterator it = _finsh; while (pos < it) { *it = *(it - 1); --it; } *pos = x; ++_finsh; } //随机位置的删除 void Erase(Iterator pos) { if (Empty()) { assert(false); return; } Iterator Cur = pos; Iterator end = End(); while (Cur < end) { *Cur = *(Cur + 1); ++Cur; } --_finsh; } void _Destroy() { if (_start != NULL) { delete[]_start; } _start = _finsh = _EndOfStorage = NULL; } size_t Size() { return _finsh - _start; } size_t Capacity() { return _EndOfStorage - _start; } //迭代器的操作 public: Iterator Begin() { return _start; } Iterator End() { return _finsh; } bool Empty() const { return Begin() == End(); } ConstIterator Begin() const { return _start; } ConstIterator End() const { return _finsh; } T& operator[](size_t indes) { assert(indes < Size()); return _start[indes]; } const T& operator[](size_t indes) const { assert(indes < Size()); return _start[indes]; } //增容 protected: void _Expand(size_t n) { assert(n > 0); assert(n > Capacity()); T*tmp = new T ; if (_start) { //memcpy()(string)存在浅拷贝 for (size_t i = 0; i < Size(); ++i) { tmp[i] = _start[i]; } delete[] _start; } size_t size = Size(); _start = tmp; _finsh = _start + size; _EndOfStorage = _start + n; } protected: Iterator _start; Iterator _finsh; Iterator _EndOfStorage; };测试函数
cpp文件 #include"Vector.h" void PrintVector(const Vector<int> &v) { Vector<int> ::ConstIterator it = v.Begin(); while (it != v.End()) { cout << *it << " "; ++it; } cout << endl; } void TestVector() { Vector<int> v; v.PushBack(1); v.PushBack(2); v.PushBack(3); v.PushBack(4); PrintVector(v); v.PopBack(); v.PopBack(); v.PopBack(); v.PopBack(); PrintVector(v); } int main() { TestVector(); system("pause"); return 0; }
在这里面尤其注意的是在随机位置的插入Insert() 函数和随机位置的删除Erase() 函数:
1:此时的pos是个迭代器;挪动数据通过指针实现;
2:在进行插入时要进行容量检查,删除时要进行判空。
相关文章推荐
- STL-模拟实现vector(含类型萃取)
- 【STL】模拟实现vector
- 【STL】 vector 模拟实现
- 模拟实现STL-Vector
- STL模拟实现vector
- 模拟实现STL中的vector
- STL vector的模拟实现
- 类模板模拟实现STL中Vector
- 【STL】vector的模拟实现
- STL中vector的使用以及模拟实现
- 模拟实现STL中的Vector容器
- STL库中的vector的使用和模拟实现
- 模拟实现STL (双)链表
- STL-vector的实现
- STL vector list deque区别与实现
- 动手实现自己的 STL 容器 《1》---- vector
- C++面试题:介绍一下STL,STL如何实现vector
- 模仿stl实现自己的vector
- 【STL】迭代器与List的模拟实现
- STL中vector,Map,Set的实现原理