1:vector各函数接口
cpp
#pragma once
#include <iostream>
using namespace std;
namespace MyVector
{
template <class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//默认成员函数
vector();//构造函数
vector(size_t n, const T& val);//构造函数
template <class InputIterator>
vector(InputIterator first, InputIterator last);//迭代器区间构造
vector (const vector<T> v);//拷贝构造函数
vector<T>& operator=(const vector<T>& x);//赋值运算符重载
~vector();//析构函数
//迭代器相关函数
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
//容量相关函数
size_t size() const;
size_t capacity() const;
void reserve(size_t n);
void resize(size_t n, const T& val = T());
bool empty() const;
//元素访问相关函数
T& operator[](size_t n);
const T& operator[](size_t n) const;
//修改容器相关函数
void push_back(const T& val);
void pop_back();
iterator insert(iterator position, const T& val);
iterator erase(iterator position);
void swap(vector <T>& v1);
private:
iterator start;//指向数组起始位置
iterator finish;//指向数组最后一个元素的下一个位置
iterator end_of_storage;//指向数组的最后位置
};
}
- PS:为了防止和标准库中的进行冲突,所以使用命名空间将其包裹起来.
2:vector当中的成员变量介绍

- _start:指向容器的头.
- _end:指向有效数据的尾.
- _endofstorage:指向整个容器的尾部.
3:默认成员函数
3.1:构造函数1
cpp
//默认成员函数
vector()
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
}
vector首先支持一个无参的构造函数,对于这个无参的构造函数,直接将构造对象的三个成员变量都设置为空指针即可.
3.2:构造函数2
cpp
vector(size_t n, const T& val)
{
_start = new T[n];
_finish = _start + n;
_end_of_storage = _finish;
for (size_t i = 0; i < n; i++)
{
_start[i] = val;
}
}
对于使用n个值去构造该容器,此时首先开辟空间,然后进行赋值即可.
cpp
vector(int n, const T& val = T())
{
//第一种写法
/* _start = new T[n];
_finish = _start + n;
_end_of_storage = _finish;
for (size_t i = 0; i < n; i++)
{
_start[i] = val;
}*/
reserve(n);
//填充val
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
可以看到,这个重载函数与之不同的就是其参数n的类型不同,但这却是必要的,否则当我们使用以下代码时,编译器会优先与构造函数3相匹配,甚至无法通过编译


3.3:构造函数3
cpp
//迭代器区间构造,类模板的成员函数可以是函数模板
//类模板的成员函数可以是函数模板
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector还支持使用一段迭代器区间进行对象的构造。因为该迭代器区间可以是其他容器的迭代器区间,也就是说该函数接收到的迭代器的类型是不确定的,所以我们这里需要将该构造函数设计为一个函数模板,在函数体内将该迭代器区间的数据一个个尾插到容器当中即可。
3.4:拷贝构造函数
3.4.1:第一种写法
cpp
//v2(v1),拷贝构造函数
vector(const vector<T> & v)
{
T* Tmp = new T[v.size()];
//拷贝数据
for (size_t i = 0; i < v.size(); i++)
{
Tmp[i] = v[i];
}
_start = Tmp;
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
对于拷贝构造函数,就是直接开辟一块与该容器大小相同的函数,然后将该容器中的数据一个个拷贝过来即可,然后再更新_finish与_end_of_storage即可.
3.4.2:第二种写法
cpp
//v2(v1),拷贝构造函数
vector(const vector<T> & v)
{
//第二种写法
reserve(v.capacity());
for(size_t i = 0; i < v.size(); i++)
{
push_back(v[i]);
}
}
3.5:赋值运算符重载
cpp
//返回引用的目的是为能够连续赋值
vector<T>& operator=( vector<T> & v)//赋值运算符重载
{
//防止自己给自己赋值
if(this != &v)
{
//释放原有空间
delete[] _start;
//开辟新空间
T* Tmp = new T[v.size()];
//拷贝数据
for (size_t i = 0; i < v.size(); i++)
{
Tmp[i] = v[i];
}
_start = Tmp;
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
//为支持连续赋值
return *this;
}
首先判断是否是给自己赋值,若是给自己赋值则无需进行操作。若不是给自己赋值,则先开辟一块和容器v大小相同的空间,然后将容器v当中的数据进行拷贝,最后更新_finish和_endofstorage的值即可。
3.6:析构函数
cpp
~vector()
{
if(_start != nullptr)
{
delete[]_start;
_start = _finish = _end_of_storage = nullptr;
}
}
对容器进行析构时,首先判断该容器是否为空容器,若为空容器,则无需进行析构操作,若不为空,则先释放空间,然后将容器的各个成员变量设置为空指针即可。
4:迭代器相关函数
4.1:begin与end
cpp
//迭代器相关函数
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
- vector当中的begin函数返回容器的首地址,end函数返回容器当中有效数据的下一个数据的地址。
- 除此之外,还需要对其进行重载,因为存在const对象,所以需要重载begin与end函数,使得const对象能访问到对应的迭代器,但const对象访问到的迭代器只能对数据进行读操作,不能够对其进行修改.
5:容量和大小相关函数
5.1:size与capacity
cpp
//容量相关函数
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _end_of_storage - _start;
}

根据vector中三个成员变量各自的指向,很容易得到当前容器中的有效数据个数和最大容量.
由于两个指针相减的结果,就是两个之间的元素个数,因此
- size = _start - _end;
- capacity = _endofstorage - _start;
5.2:reserve
- 当n > capacity时,此时将capacity扩容到n或者大于n.
- 当n < capacity时,此时什么也不做.
cpp
//大于capacity时,才会进行扩容
void reserve(size_t n)
{
if(n > capacity() )
{
//开辟新空间
T* Tmp = new T[n];
size_t oldsize = size();
//拷贝原有数据
for(size_t i = 0; i < oldsize; i++)
{
Tmp[i] = _start[i];
}
//释放旧空间
delete[]_start;
_start = Tmp;
//由于旧空间被释放了,因此要保存旧空间的size,方便finish移动
_finish = _start + oldsize;
_end_of_storage = _start + n;
}
}
- 判断n 是否大于capacity.
- 大于n,首先开辟新空间,并且保留旧空间的有效数据个数.
- 拷贝原有数据.
- 释放旧空间,将新开辟的空间交给容器维护.
- 更新成员变量的值.
5.2.1:拷贝数据问题
有的uu会好奇,为什么在拷贝数据的时候,不使用memcpy去拷贝数据呢?memcpy走的是浅拷贝,可能uu们会想,当vector当中存储的是string的时候**,虽然使用memcpy函数reserve出来的容器与原容器当中每个对应的string成员都指向同一个字符串空间,** 但是原容器存储数据的空间不是已经被释放了,相当于现在只有一个容器维护这这些字符串空间,这还有什么影响呢,可是当释放旧空间的时候,会自动调用string的析构函数,将其指向的字符串也进行释放,
所以使用memcpy函数reserve出来的容器当中的每一个string所指向的字符串实际上是一块已经被释放的空间,访问该容器时就是对内存空间进行非法访问。


5.3:resize
- 当n < size时,此时将容器的size缩容至n,但不改变capacity.
- 当n > size时,此时将size扩大到n,扩大的数据为val,若val未给出,则用0填充.
cpp
void resize(size_t n, const T& val = T())
{
if(n < size())
{
_finish = _start + n;
}
else
{
//大于capacity时,才会进行扩容
if (n > capacity())
{
reserve(n);
}
while (_finish != _start + n)
{
*_finish = val;
_finish++;
}
}
}
5.4:empty
empty函数可以直接通过比较容器当中的_start和_finish指针的指向来判断容器是否为空,若所指位置相同,则该容器为空。
cpp
bool empty() const
{
return _start == _finish;
}
6:修改容器内容相关函数
6.1:push_back
要尾插数据首先得判断容器是否已满,若已满则需要先进行扩容,然后将数据尾插到_finish指向的位置,再将_finish++即可。
cpp
void push_back(const T& val)
{
//先判断容量是否够用
if(_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : this->capacity() * 2;
reserve(newcapacity);
}
*_finish = val;
_finish++;
}
6.2:pop_back
尾删数据之前也得先判断容器是否为空,若不为空则将_finish--即可。
cpp
void pop_back()
{
//确保容器不为空
if(!empty())
{
_finish--;
}
}
6.3:insert
insert函数可以在所给迭代器pos位置插入数据,在插入数据前先判断是否需要增容,然后将pos位置及其之后的数据统一向后挪动一位,以留出pos位置进行插入,最后将数据插入到pos位置即可
cpp
void insert(iterator position, const T& val)
{
assert(position >= begin() && position <= end());
//先判断容量是否够用
if(_finish == _end_of_storage)
{
size_t newcapacity = this->capacity() == 0 ? 4 : this->capacity() * 2;
size_t pos = position - begin();//记录插入位置
reserve(newcapacity);
position = begin() + pos;//更新插入位置
}
iterator it = _finish - 1;
//将元素后移
while(it >= position)
{
*(it + 1) = *it;
it--;
}
*position = val;
_finish++;
}

若需要增容,则需要在增容前记录pos与_start之间的间隔,然后通过该间隔确定在增容后的容器当中pos的指向,否则pos还指向原来被释放的空间。
6.4:erase
erase函数可以删除所给迭代器pos位置的数据,在删除数据前需要判断容器是否为空,若为空则需做断言处理,删除数据时直接将pos位置之后的数据统一向前挪动一位,将pos位置的数据覆盖即可,
cpp
iterator erase(iterator position)
{
assert(!empty());
iterator it = position + 1;
//将元素前移
while(it != _finish)
{
//从后往前移
*(it - 1) = *it;
it++;
}
_finish--;
return position;
}
6.5:swap
swap函数用于交换两个容器的数据,我们可以直接调用库当中的swap函数将两个容器当中的各个成员变量进行交换即可。
cpp
void swap(vector <T>& v1)
{
std::swap(_start, v1._start);
std::swap(_finish, v1._finish);
std::swap(_end_of_storage, v1._end_of_storage);
}
7:访问容器相关函数
cpp
T& operator[](size_t n)
{
return _start[n];
}
const T& operator[](size_t n) const
{
return _start[n];
}
8:相关测试
8.1:测试默认成员函数
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"
void TestDefaultMemberFunctions()
{
MyVector::vector<int> v1;
MyVector::vector<int> v2(10,5);
MyVector::vector<int> v3;
v3 = v2;
MyVector::vector<int> v4(v3);
MyVector::vector<int> v5(v2.begin(),v2.end());
}
int main()
{
TestDefaultMemberFunctions();
return 0;
}


8.2:测试迭代器相关函数
cpp
void TestIterator()
{
MyVector::vector<int> v1(10, 1);
//使用迭代器遍历
MyVector::vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//使用const_iterator遍历
const MyVector::vector<int> v2 = v1;
for (MyVector::vector<int>::const_iterator it = v2.begin(); it != v2.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}

8.3:测试容量与大小相关函数
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"
void TestContainerRelatedFunctions()
{
MyVector::vector<int> v1;
cout << "v1 size: " << v1.size() << ", capacity: " << v1.capacity() << ", empty: " << v1.empty() << endl;
v1.reserve(15);
cout << "After reserve(15), v1 size: " << v1.size() << ", capacity: " << v1.capacity() << endl;
v1.resize(10, 3);
cout << "After resize(10, 3), v1 size: " << v1.size() << ", capacity: " << v1.capacity() << endl;
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
}
int main()
{
//TestDefaultMemberFunctions();
//TestIterator();
TestContainerRelatedFunctions();
return 0;
}

8.4:测试尾插与尾删
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"
void TestPushBackAndPopBack()
{
MyVector::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
MyVector::vector<int>::iterator it = v1.begin();
while(it != v1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
v1.pop_back();
v1.pop_back();
it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
it++;
}
}
int main()
{
TestPushBackAndPopBack();
return 0;
}

8.5:测试insert与erase与Swap
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"
void TestInsertAndEraseAndSwap()
{
MyVector::vector<int> v1(8,5);
v1.insert(v1.begin(), 10);
v1.insert(v1.begin() + 2, 10);
v1.insert(v1.end(), 10);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
v1.erase(v1.begin());
v1.erase(v1.begin() + 1);
v1.erase(v1.end() - 1);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
MyVector::vector<int> v2;
v1.swap(v2);
}
int main()
{
TestInsertAndEraseAndSwap();
return 0;
}


9:总代码
9.1:vector.h
cpp
#pragma once
#include <iostream>
using namespace std;
#include <assert.h>
#include <string>
namespace MyVector
{
template <class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//默认成员函数
vector()
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
}
//使用n个val值构造vector
vector(size_t n, const T& val = T())
{
//第一种写法
/* _start = new T[n];
_finish = _start + n;
_end_of_storage = _finish;
for (size_t i = 0; i < n; i++)
{
_start[i] = val;
}*/
reserve(n);
//填充val
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
vector(int n, const T& val = T())
{
//第一种写法
/* _start = new T[n];
_finish = _start + n;
_end_of_storage = _finish;
for (size_t i = 0; i < n; i++)
{
_start[i] = val;
}*/
reserve(n);
//填充val
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
//v2(v1),拷贝构造函数
vector(const vector<T> & v)
{
//T* Tmp = new T[v.size()];
////拷贝数据
//for (size_t i = 0; i < v.size(); i++)
//{
// Tmp[i] = v[i];
//}
//_start = Tmp;
//_finish = _start + v.size();
//_end_of_storage = _start + v.capacity();
//第二种写法
reserve(v.capacity());
for(size_t i = 0; i < v.size(); i++)
{
push_back(v[i]);
}
}
//迭代器区间构造,类模板的成员函数可以是函数模板
//类模板的成员函数可以是函数模板
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
//返回引用的目的是为能够连续赋值
vector<T>& operator=( vector<T> & v)//赋值运算符重载
{
//防止自己给自己赋值
if(this != &v)
{
//释放原有空间
delete[] _start;
//开辟新空间
T* Tmp = new T[v.size()];
//拷贝数据
for (size_t i = 0; i < v.size(); i++)
{
Tmp[i] = v[i];
}
_start = Tmp;
_finish = _start + v.size();
_end_of_storage = _start + v.capacity();
}
//为支持连续赋值
return *this;
}
~vector()
{
if(_start != nullptr)
{
delete[]_start;
_start = _finish = _end_of_storage = nullptr;
}
}
//迭代器相关函数
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
//容量相关函数
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _end_of_storage - _start;
}
//大于capacity时,才会进行扩容
void reserve(size_t n)
{
if(n > capacity() )
{
//开辟新空间
T* Tmp = new T[n];
size_t oldsize = size();
//拷贝原有数据
for(size_t i = 0; i < oldsize; i++)
{
Tmp[i] = _start[i];
}
//memcpy的本质是浅拷贝
//memcpy(Tmp,_start,size() * sizeof(T));
//释放旧空间
delete[]_start;
_start = Tmp;
//由于旧空间被释放了,因此要保存旧空间的size,方便finish移动
_finish = _start + oldsize;
_end_of_storage = _start + n;
}
}
void resize(size_t n, const T& val = T())
{
if(n < size())
{
_finish = _start + n;
}
else
{
//扩容
reserve(n);
//填充val
while (_finish != _start + n)
{
*_finish = val;
_finish++;
}
}
}
bool empty() const
{
return _start == _finish;
}
//元素访问相关函数
T& operator[](size_t n)
{
return _start[n];
}
const T& operator[](size_t n) const
{
return _start[n];
}
//修改容器相关函数
void push_back(const T& val)
{
//先判断容量是否够用
/*if(_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : this->capacity() * 2;
reserve(newcapacity);
}
*_finish = val;
_finish++;*/
insert(end(), val);
}
void pop_back()
{
//确保容器不为空
if(!empty())
{
_finish--;
}
}
void insert(iterator position, const T& val)
{
assert(position >= begin() && position <= end());
//先判断容量是否够用
if(_finish == _end_of_storage)
{
size_t newcapacity = this->capacity() == 0 ? 4 : this->capacity() * 2;
size_t pos = position - begin();//记录插入位置
reserve(newcapacity);
position = begin() + pos;//更新插入位置
}
iterator it = _finish - 1;
//将元素后移
while(it >= position)
{
*(it + 1) = *it;
it--;
}
*position = val;
_finish++;
}
iterator erase(iterator position)
{
assert(!empty());
iterator it = position + 1;
//将元素前移
while(it != _finish)
{
//从后往前移
*(it - 1) = *it;
it++;
}
_finish--;
return position;
}
void swap(vector <T>& v1)
{
std::swap(_start, v1._start);
std::swap(_finish, v1._finish);
std::swap(_end_of_storage, v1._end_of_storage);
}
private:
iterator _start = nullptr;//指向数组起始位置
iterator _finish = nullptr;//指向数组最后一个元素的下一个位置
iterator _end_of_storage = nullptr; //指向数组的最后位置
};
}
9.2:Test.cpp
cpp
#define _CRT_SECURE_NO_WARNINGS
#include "vector.h"
void TestDefaultMemberFunctions()
{
MyVector::vector<int> v1;
MyVector::vector<int> v2(10,5);
MyVector::vector<int> v3;
v3 = v2;
MyVector::vector<int> v4(v3);
MyVector::vector<int> v5(v2.begin(),v2.end());
}
void TestIterator()
{
MyVector::vector<int> v1(10, 1);
//使用迭代器遍历
MyVector::vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//使用const_iterator遍历
const MyVector::vector<int> v2 = v1;
for (MyVector::vector<int>::const_iterator it = v2.begin(); it != v2.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void TestContainerRelatedFunctions()
{
MyVector::vector<int> v1;
cout << "v1 size: " << v1.size() << ", capacity: " << v1.capacity() << ", empty: " << v1.empty() << endl;
v1.reserve(15);
cout << "After reserve(15), v1 size: " << v1.size() << ", capacity: " << v1.capacity() << endl;
v1.resize(10, 3);
cout << "After resize(10, 3), v1 size: " << v1.size() << ", capacity: " << v1.capacity() << endl;
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
}
void TestPushBackAndPopBack()
{
MyVector::vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
MyVector::vector<int>::iterator it = v1.begin();
while(it != v1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
v1.pop_back();
v1.pop_back();
it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
it++;
}
}
void TestInsertAndEraseAndSwap()
{
MyVector::vector<int> v1(8,5);
v1.insert(v1.begin(), 10);
v1.insert(v1.begin() + 2, 10);
v1.insert(v1.end(), 10);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
v1.erase(v1.begin());
v1.erase(v1.begin() + 1);
v1.erase(v1.end() - 1);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
MyVector::vector<int> v2;
v1.swap(v2);
}
int main()
{
//TestDefaultMemberFunctions();
//TestIterator();
//TestContainerRelatedFunctions();
//TestMemcpy();
//TestPushBackAndPopBack();
TestInsertAndEraseAndSwap();
return 0;
}