前言
vector是很重要的数据结构,所以了解它的底层的核心原理是很有必要的,如何了解它的底层原理呢?除了阅读原码外,自己实现一下vector的核心逻辑也是不错的选择。
目录
1.四个默认成员函数
2.迭代器的实现
3.增删查改
4. 容量相关
5.完整代码
6.测试相关
7.memcpy深浅拷贝问题
1.四个默认成员函数
//构造函数
vector()
:_start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
}
vector(size_t n, const T& val)
:_start(new T[n])
, _finish(_start + n)
, _endOfStorage(_start + n)
{
for (int i = 0; i < n; i++)
{
_start[i] = val;
}
}
//防止上面的在调用的时候被解析为迭代器区间的调用
vector(int n, const T& val)
:_start(new T[n])
, _finish(_start + n)
, _endOfStorage(_start + n)
{
for (int i = 0; i < n; i++)
{
_start[i] = val;
}
}
//使用迭代器构造
template <typename InputIterator>//使用模板函数便于支持各种类型的迭代器
vector(InputIterator first,InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
//拷贝构造
/*vector(const vector<T>& x)
:_start(new T[x.capacity()])
{
for (size_t i = 0; i < (int)x.size(); i++)
{
_start[i] = x[i];
}
_finish = _start+(x.size());
_endOfStorage = _start + (x.capacity());
}*/
//简洁写法
vector(const vector<T>& x)
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{
reserse(x.capacity());//提前开辟空间
size_t i = 0;
for (i = 0; i < x.size(); ++i)
{
push_back(x[i]);//拷贝数据
}
}
//vector<T> operator=(const vector<T>& x)//默认成员函数
//{
// T* tmp = new T[x.capacity()];//开新空间
// for (size_t i = 0; i < (int)x.size(); i++)//拷贝数据
// {
// //memcpy(tmp, _start, sizeof(T) * x.capacity();
// tmp[i] = x._start[i];
// }
// delete[]_start;
// _start = tmp;
// _finish = _start + (x.size());
// _endOfStorage = _start + (x.capacity());
// return *this;//为了支持连等
//}
//现代写法
void swap(vector<T>& x)//交换函数
{
::swap(_start,x._start);//调用全局的swap函数
::swap(_finish, x._finish);
::swap(_endOfStorage, x._endOfStorage);
}
vector<T> operator=(vector<T> x)//默认成员函数
{
swap(x);
return *this;
}
const vector<T> operator=(const vector<T>& x)const //const类型
{
T* tmp = new T[x.capacity()];//开新空间
for (int i = 0; i < (int)x.size(); i++)//拷贝数据
{
tmp[i] = x._start[i];
}
delete[]_start;
_start = tmp;
_finish = _start + (x.size());
_endOfStorage = _start + (x.capacity());
return *this;//为了支持连等
}
//析构
~vector()
{
delete[]_start;//释放空间
_start = _finish = _endOfStorage = nullptr;//指针置空
}
2.迭代器的实现
typedef T* iterator;//vector的迭代器是原生指针
typedef const T* const_iterator;
//迭代器
iterator& begin()
{
return _start;
}
const_iterator& begin()const //const类型的迭代器
{
return _start;
}
iterator& end()
{
return _finish;
}
const_iterator& end()const
{
return _finish;
}
3.增删查改
T& front()//返回第一个元素
{
assert(_start);
return *_start;
}
T& back()//返回末尾的元素
{
assert(_finish-1);
return *(_finish-1);
}
//尾插
void push_back(const T& val)
{
//if (_finish == _endOfStorage)//增容
//{
// int n = 0;
// if (capacity() == 0)
// n = 2;
// else
// n=capacity() * 2;
// reserse(n);
// _endOfStorage = _start + n;
//}
//_start[size()] = val;//插入数据
//++_finish;
insert(end(), val);//复用insert
}
//尾删
void pop_back()
{
assert(size());
/*--_finish;*/
erase(end()-1);//复用erase
}
iterator insert(iterator pox, const T& data)//pox位置的插入
{
//检查位置是否合法
assert(pox >= _start);
assert(pox <= _finish);
//检查是否需要增容
if (_finish == _endOfStorage)
{
size_t longs = size();
size_t poxN = pox - _start;
if (longs == 0)
longs = 2;
reserse(2 * longs);
pox = _start + poxN;
}
iterator end = _finish -1;
while (end >= pox)//挪动数据
{
*(end + 1) = *end;
--end;
}
*pox = data;//插入数据
++_finish;
return pox + 1;
}
iterator erase(iterator pox)//pox位置的删除
{
assert(pox >= _start);
assert(pox < _finish);
iterator pox1 = pox;
//挪动数据
while (pox1<_finish)
{
*pox1 = *(pox1 + 1);
++pox1;
}
--_finish;
return pox;
}
4. 容量相关
//容量相关的操作
size_t size()const//这样const和非const对象就都可以调用了。
{
return _finish - _start;
}
size_t capacity()const//这样const和非const对象就都可以调用了。
{
return _endOfStorage - _start;
}
bool empty()//是否为空
{
return _finish == _start;
}
bool empty()const//是否为空
{
return _finish == _start;
}
void reserse(int n)//改变空间的大小
{
if (n > (int)capacity())//增容
{
size_t oldSize = size();//保存size的值
T* tmp = new T[n];//开辟新空间
if (_start)//防止指针为空
{
//拷贝数据
//
for (int i = 0; i < (int)oldSize; i++)
{
tmp[i] = _start[i];
}
delete[]_start;//释放旧空间
}
_start = tmp;
_finish =_start + oldSize;
_endOfStorage = _start + n;
}
}
void resize(int n, const T& value=T())
{
if (n < (int)size())//只需要改变size的大小
{
_finish = _start + n;
}
else
{
if (n <= (int)capacity())//不用扩容直接插入value
{
while (_finish != _endOfStorage)//
{
*(_finish) = value;
++_finish;
}
}
else//扩容
{
size_t oldSize = size();
T* tmp = new T[n];//开新空间,拷贝数据
for (size_t i = 0; i < size(); i++)
{
tmp[i] = _start[i];
}
delete[]_start;
_start = tmp;
_finish = _start + oldSize;
_endOfStorage = _start + n;
while (_finish != _endOfStorage)//插入value值
{
*(_finish) = value;
++_finish;
}
}
}
}
5.完整代码
#pragma once
#include<string.h>
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
namespace qyy
{
template <class T>
class vector
{
public:
typedef T* iterator;//vector的迭代器是原生指针
typedef const T* const_iterator;
//构造函数
vector()
:_start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
}
vector(size_t n, const T& val)
:_start(new T[n])
, _finish(_start + n)
, _endOfStorage(_start + n)
{
for (int i = 0; i < n; i++)
{
_start[i] = val;
}
}
//防止上面的在调用的时候被解析为迭代器区间的调用
vector(int n, const T& val)
:_start(new T[n])
, _finish(_start + n)
, _endOfStorage(_start + n)
{
for (int i = 0; i < n; i++)
{
_start[i] = val;
}
}
//使用迭代器构造
template <typename InputIterator>//使用模板函数便于支持各种类型的迭代器
vector(InputIterator first,InputIterator last)
{
while (first != last)
{
push_back(*first);//调用push_back填入数据
++first;
}
}
//拷贝构造
/*vector(const vector<T>& x)
:_start(new T[x.capacity()])
{
for (size_t i = 0; i < (int)x.size(); i++)
{
_start[i] = x[i];
}
_finish = _start+(x.size());
_endOfStorage = _start + (x.capacity());
}*/
//简洁写法
vector(const vector<T>& x)
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{
reserse(x.capacity());//提前开辟空间
size_t i = 0;
for (i = 0; i < x.size(); ++i)
{
push_back(x[i]);//拷贝数据
}
}
//vector<T> operator=(const vector<T>& x)//默认成员函数
//{
// T* tmp = new T[x.capacity()];//开新空间
// for (size_t i = 0; i < (int)x.size(); i++)//拷贝数据
// {
// //memcpy(tmp, _start, sizeof(T) * x.capacity();
// tmp[i] = x._start[i];
// }
// delete[]_start;
// _start = tmp;
// _finish = _start + (x.size());
// _endOfStorage = _start + (x.capacity());
// return *this;//为了支持连等
//}
//现代写法
void swap(vector<T>& x)//交换函数
{
::swap(_start,x._start);//调用全局的swap函数
::swap(_finish, x._finish);
::swap(_endOfStorage, x._endOfStorage);
}
vector<T> operator=(vector<T> x)//默认成员函数
{
swap(x);
return *this;
}
const vector<T> operator=(const vector<T>& x)const //const类型
{
T* tmp = new T[x.capacity()];//开新空间
for (int i = 0; i < (int)x.size(); i++)//拷贝数据
{
tmp[i] = x._start[i];
}
delete[]_start;
_start = tmp;
_finish = _start + (x.size());
_endOfStorage = _start + (x.capacity());
return *this;//为了支持连等
}
//析构
~vector()
{
delete[]_start;//释放空间
_start = _finish = _endOfStorage = nullptr;//指针置空
}
//迭代器
iterator& begin()
{
return _start;
}
const_iterator& begin()const //const类型的迭代器
{
return _start;
}
iterator& end()
{
return _finish;
}
const_iterator& end()const
{
return _finish;
}
void reserse(int n)//改变空间的大小
{
if (n > (int)capacity())//增容
{
size_t oldSize = size();//保存size的值
T* tmp = new T[n];//开辟新空间
if (_start)//防止指针为空
{
//拷贝数据
//
for (int i = 0; i < (int)oldSize; i++)
{
tmp[i] = _start[i];
}
delete[]_start;//释放旧空间
}
_start = tmp;
_finish =_start + oldSize;
_endOfStorage = _start + n;
}
}
void resize(int n, const T& value=T())
{
if (n < (int)size())//只需要改变size的大小
{
_finish = _start + n;
}
else
{
if (n <= (int)capacity())//不用扩容直接插入value
{
while (_finish != _endOfStorage)//
{
*(_finish) = value;
++_finish;
}
}
else//扩容
{
size_t oldSize = size();
T* tmp = new T[n];//开新空间,拷贝数据
for (size_t i = 0; i < size(); i++)
{
tmp[i] = _start[i];
}
delete[]_start;
_start = tmp;
_finish = _start + oldSize;
_endOfStorage = _start + n;
while (_finish != _endOfStorage)//插入value值
{
*(_finish) = value;
++_finish;
}
}
}
}
T& operator[](size_t x)//元素访问
{
assert(x < size());
return *(_start + x);
}
const T& operator[](size_t x)const//用于const成员调用
{
assert(x < size());
return *(_start + x);
}
//尾插
void push_back(const T& val)
{
//if (_finish == _endOfStorage)//增容
//{
// int n = 0;
// if (capacity() == 0)
// n = 2;
// else
// n=capacity() * 2;
// reserse(n);
// _endOfStorage = _start + n;
//}
//_start[size()] = val;//插入数据
//++_finish;
insert(end(), val);//复用insert
}
//尾删
void pop_back()
{
assert(size());
/*--_finish;*/
erase(end()-1);//复用erase
}
iterator insert(iterator pox, const T& data)//pox位置的插入
{
//检查位置是否合法
assert(pox >= _start);
assert(pox <= _finish);
//检查是否需要增容
if (_finish == _endOfStorage)
{
size_t longs = size();
size_t poxN = pox - _start;
if (longs == 0)
longs = 2;
reserse(2 * longs);
pox = _start + poxN;
}
iterator end = _finish -1;
while (end >= pox)//挪动数据
{
*(end + 1) = *end;
--end;
}
*pox = data;//插入数据
++_finish;
return pox + 1;
}
iterator erase(iterator pox)//pox位置的删除
{
assert(pox >= _start);
assert(pox < _finish);
iterator pox1 = pox;
//挪动数据
while (pox1<_finish)
{
*pox1 = *(pox1 + 1);
++pox1;
}
--_finish;
return pox;
}
//容量相关的操作
size_t size()const//这样const和非const对象就都可以调用了。
{
return _finish - _start;
}
size_t capacity()const//这样const和非const对象就都可以调用了。
{
return _endOfStorage - _start;
}
bool empty()//是否为空
{
return _finish == _start;
}
bool empty()const//是否为空
{
return _finish == _start;
}
T& front()//返回第一个元素
{
assert(_start);
return *_start;
}
T& back()//返回末尾的元素
{
assert(_finish-1);
return *(_finish-1);
}
private:
iterator _start;
iterator _finish;
iterator _endOfStorage;
};
}
6.测试相关
#define _CRT_SECURE_NO_WARNINGS 1
#include"vector.h"
void testVector1()
{
qyy::vector<int> v1;
qyy::vector<int> v2(5, 2);
qyy::vector<int> v3(v2);
v2 = v3;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.pop_back();
}
void testVector2()
{
qyy::vector<int> v1;
qyy::vector<int> v2(10, 5);
int array[] = { 1,2,3,4,5 };
qyy::vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));
qyy::vector<int> v4(v3);
for (size_t i = 0; i < v2.size(); ++i)
{
cout << v2[i] << " ";
}
cout << endl;
auto it = v3.begin();
while (it != v3.end())
{
cout << *it << " ";
++it;
}
cout << endl;
for (auto e : v4)
{
cout << e << " ";
}
cout << endl;
}
void testVector3()
{
qyy::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.resize(12,3);
cout << v.size() << endl;
cout << v.capacity() << endl;
cout << v.front() << endl;
cout << v.back() << endl;
cout << v[0] << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.pop_back();
v.pop_back();
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.insert(v.begin(), 0);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.erase(v.begin() + 1);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
qyy::vector<string> v2;
v2.push_back("1111111");
v2.push_back("2222222");
v2.push_back("3333333");
v2.push_back("4444444");
v2.push_back("5555555");
for (auto& e : v2)
cout << e<<" ";
}
int main()
{
//testVector();
testVector2();
testVector3();
int i = int();//c++支持内置类型像自定义类型一样调用匿名的构造函数
double f = double();
return 0;
}
7.memcpy深浅拷贝问题
如果我们的reserse函数是以下面这种方式实现的:
void reserse(int n)//改变空间的大小
{
if (n > (int)capacity())//增容
{
size_t oldSize = size();//保存size的值
T* tmp = new T[n];//开辟新空间
if (_start)//防止指针为空
{
//拷贝数据
memcpy(tmp,_start,sizof(T)*n)
delete[]_start;//释放旧空间
}
_start = tmp;
_finish =_start + oldSize;
_endOfStorage = _start + n;
}
}
其他地方都没有改变,运行我们的测试代码,程序就会奔溃,因为此时在testVector3函数中,使用了自定义类型string来实例化vector。所以在v2中存储的是string对象,而memcpy只能完成浅拷贝,扩容后只是将v2成员指针指向旧空间的string对象,没有为v2中指针指向的string对象开辟新的空间,此时delete []_start;释放旧空间,就会使得v2成员指向的string对象的空间失效,再进行其他操作程序就会奔溃(此时v2中成员指向的空间已经被操作系统回收)。
如图:
正确的操作是扩容以后调用自定义类型的深拷贝函数,也就是operator=。如下:
void reserse(int n)//改变空间的大小
{
if (n > (int)capacity())//增容
{
size_t oldSize = size();//保存size的值
T* tmp = new T[n];//开辟新空间
if (_start)//防止指针为空
{
//拷贝数据
for (int i = 0; i < (int)oldSize; i++)
{
tmp[i] = _start[i];//调用string的深拷贝函数
}
delete[]_start;//释放旧空间
}
_start = tmp;
_finish =_start + oldSize;
_endOfStorage = _start + n;
}
}