您的位置:首页 > 其它

【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:在进行插入时要进行容量检查,删除时要进行判空。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: