博客主页:C-SDN花园GGbond
⏩ 文章专栏:玩转c++
目录
1. vector的成员变量
2. vector的成员函数
2.1. vector的迭代器
2.2. vector的初始化与销毁
2.2.1. 构造函数与拷贝构造
2.2.2. 赋值重载与析构函数
2.3. vector的容量操作
2.3.1. 有效长度与容量大小
2.3.2. 容量操作
2.4. vector的访问操作
2.5. vector的修改操作
2.5.1. 常见的修改操作
3. 源码
3.1 vector.h
3.2 test.cpp
3.3 运行结果
为了让我们更加深入理解vector
,接下来我们将模拟实现一个·简易版的vector
。而为了和STL
库中的vecotr
以示区分,我们将使用命名空间HTD对其封装。
vector
的底层其实就是我们之前在数据结构学习的顺序表,但是与顺序表不同的是vector
的成员变量是三个迭代器,也可以说是三个指针。
其中_start
指向起始位置,_finish
指向有效数据末尾的后一个位置,最后_end_of_storage
指向容量大小末尾的后一个位置。
namespace betty
{
template
class vector
{
public:
//...
private:
iterator _start;//指向有效数据的头
iterator _finish;//指向有效数据的尾
iterator _end_of_storage;//指向容量的尾
};
}
首先我们来模拟实现一下迭代器iterator
,而在vector
中迭代器iterator
与string
中的迭代器类似就是一个指针。所以我们直接使用typedef
实现
typedef char* iterator;//普通迭代器
typedef const char* const_iterator;//const迭代器
接下来我们来实现begin()
与end()
,其中begin()
指向的是数组的起始位置即_start
,而end
指向有效长度最后的下一位即_finish
的位置。 实现完普通迭代器之后,我们可以顺便重载一个const_iterator
的版本。
iterator begin()
{
return _first;
}
iterator end()
{
return _finish;
}
//反向迭代器
const_iterator begin()const
{
return _first;
}
const_iterator end()const
{
return _finish;
}
我们知道在vector
中还有一个反向迭代器,这个我们在之后会统一实现。
我们之前在学习vector
时知道其初始化方式有很多,可以通过默认构造函数给其初始化,n个val初始化,也可以通过迭代器初始化。
首先我们写一个默认构造函数,将其所有变量都设为空。
vector()//无参默认构造
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
vector(size_t n,const T& val=T())//n个val初始化
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
reserve(n);
while(n--)
{
push_back(val);
}
}
vector(int n, const T& val = T())//n个val初始化
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
while(n--)
{
push_back(val);
}
}
template
vector(inputiterator fist, inputiterator last)//迭代器区间初始化
{
while (fist != last)
{
push_back(*fist);
fist++;
}
}
//拷贝构造
//vector(const vector& v)
//{
// _start = new T[v.capacity()];
// for (size_t i = 0; i < v.size(); i++)
// {
// _start[i] = v._start[i];
// }
// _finish = _start + v.size();
// _end_of_storage = _start + v.capacity();
//}
vector(const vector& v)
{
reserve(v.capacity());
for (size_t i = 0; i < v.size(); i++)
{
push_back(v._start[i]);
}
}
至于为什么要同时重载int
与size_t
两种不同类型,那是为了防止在传两个int
类型的参数时被编译器交给模版InputIterator
识别,然后报错。 拷贝构造也十分简单,直接拷贝就行,但不能利用memcpy()
等库函数进行拷贝,因为这些函数都是进行的浅拷贝。如果模版参数T
是string
,vector
等自定义类型,当程序结束回收内存时就会发生内存错误。
vector operator = (vector v)
{
swap(v);
return *this;
}
实现析构函数,只需要清理资源即可
~vector()
{
delete[]_start;
_start = _finish = _end_of_storage = nullptr;
}
首先我们先实现返回数组有效长度的size()
与容量大小的capacity()
。并且为了适配const
对象,最后用const
修饰this
指针。
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _end_of_storage - _start;
}
接下来我们来实现扩容函数reserve()
与·resize()
,其中reserve()
最简单,只要新容量大于旧容量就发生扩容,其中注意需要提前记录size
大小,防止数组异地扩容原数组释放之后找不到原数组大小。
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size();
T* tmp = new T[n];
//memcpy(tmp, _start, sizeof(T) * size());memcpy浅拷贝
for (size_t i = 0; i < size(); i++)
{
tmp[i] = _start[i];
}
delete[]_start;
_start = tmp;
_finish = _start + old_size;
_end_of_storage = _start + n;
}
}
而resize()
的逻辑就比较复杂,需要分三种情况讨论。设字符串原来有效长度为size
,容量为capacity
,新容量为n
- 当
n
时, resize
会删除有效字符到指定大小。- 当
size
时, resize
会补充有效字符(默认为0)到指定大小。- 当
n>capacity
时,resize
会补充有效字符(默认为0)到指定大小。
void resize(size_t n,const T&val=T())
{
if (n < size())
{
//更新数组大小
_finish = _start + n;
}
else
{
//扩容
reserve(n);
while (_finish != _start + n)
{
*_finish = val;
++_finish;
}
}
}
为了符合我们C语言访问数组的习惯,我们可以先重载operator[]
。当然我们也要提供两种不同的接口:可读可写与可读不可写。并且使用引用返回,减少不必要的拷贝。
T& operator[](size_t pos)//可读可写
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const//可读不可写
{
assert(pos < size());
return _start[pos];
}
们也可以实现front()
与back()
函数。
// 可读可写
char& front()
{
return _start[0];
}
char& back()
{
return _start[_size() - 1];
}
// 可读不可写
const char& front()const
{
return _start[0];
}
const char& back()const
{
return _start[_size() - 1];
}
首先我们将实现两个常用的修改函数:push_back()
与pop_back()
。
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
_finish++;
}
void pop_back()
{
--_finish;
}
随后我们来实现数组的交换swap()
函数,我们知道vector
的交换其实就是指针_start
,_finish
,_end_of_storage
的交换
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
#pragma once
#include
#include
using namespace std;
namespace HTD
{
template
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;
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _end_of_storage - _start;
}
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
_finish++;
}
void pop_back()
{
--_finish;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size();
T* tmp = new T[n];
//memcpy(tmp, _start, sizeof(T) * size());memcpy浅拷贝
for (size_t i = 0; i < size(); i++)
{
tmp[i] = _start[i];
}
delete[]_start;
_start = tmp;
_finish = _start + old_size;
_end_of_storage = _start + n;
}
}
void resize(size_t n,const T& val = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
reserve(n);
while (_finish != _start + n)
{
*_finish = val;
_finish++;
}
}
}
vector()//无参默认构造
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
vector(size_t n,const T& val=T())//n个val初始化
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
reserve(n);
while(n--)
{
push_back(val);
}
}
vector(int n, const T& val = T())//n个val初始化
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
while(n--)
{
push_back(val);
}
}
template
vector(inputiterator fist, inputiterator last)//迭代器区间初始化
{
while (fist != last)
{
push_back(*fist);
fist++;
}
}
//拷贝构造
//vector(const vector& v)
//{
// _start = new T[v.capacity()];
// for (size_t i = 0; i < v.size(); i++)
// {
// _start[i] = v._start[i];
// }
// _finish = _start + v.size();
// _end_of_storage = _start + v.capacity();
//}
vector(const vector& v)
{
reserve(v.capacity());
for (size_t i = 0; i < v.size(); i++)
{
push_back(v._start[i]);
}
}
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
vector& operator=(vector v)
{
swap(v);
return *this;
}
~vector()
{
delete[]_start;
_start = _finish = _end_of_storage=nullptr;
}
T& operator[](size_t pos)//可读可写
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const//可读不可写
{
assert(pos < size());
return _start[pos];
}
private:
iterator _start;
iterator _finish;
iterator _end_of_storage;
};
template
void print_vector(const vector& v)
{
// 规定,没有实例化的类模板里面取东西,编译器不能区分这里const_iterator
// 是类型还是静态成员变量
typename vector::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it<<" ";
++it;
}
cout << endl;
for (auto e : v)
{
cout << e<<" ";
}
cout << endl;
}
void vector_test01()
{
vector v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
/*print_vector(v1);
vector v2(v1);
print_vector(v2);*/
vector v3;
v3.push_back(33);
v3.push_back(44);
print_vector(v3);
v3 = v1;
print_vector(v3);
v1.resize(8);
print_vector(v1);
cout << v1[2]<
#include"vector.h"
int main()
{
//HTD::vector_test01();
HTD::vector_test01();
return 0;
}