大家好我是沐曦希💕
文章目录
一、前言
在模拟实现容器时候,我们需要的不是造一个更好的轮子,而是在了解原理更好理解和运用容器。
那么通过查看源码,抽出vector容器主题框架:
template <class T, class Alloc = alloc>
class vector {
typedef T value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
protected:
iterator start;
iterator finish;
iterator end_of_storage;
}
本质上与T*a,size_t size,size_t capacity是类似的:
对于size = _finish - _start
对于capacity = _endofstorage-_start
二、无参构造&析构
- 无参构造
初始化值为空。
vector()
:_start(nullptr)
,_finish(nullptr)
,_endofstarge(nullptr)
{
}
- 析构
~vector()
{
delete[] _start;
_start = _finish = _endofstarge = nullptr;
}
三、基础接口
1.empty和clear
- empty
bool empty()
{
return _finish == _start;
}
- clear
void clear()
{
_finish = _start; //这里可不能置为nullptr
}
2.size和capacity
- size
int size() const
{
return _finish - _start;
}
-capacity
int capacity() const
{
return _endofstarge - _start;
}
加const是让const类对象和非const类对象都能调用
3.[]和iterator
这里提供const和非const两个版本,加const是只可读,不能更改,不加const是可读可写。
- []
T& operator[](const size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](const size_t pos)
{
assert(pos < size())
return _start[pos];
}
- iterator
同理普通迭代器和const迭代器版本,同理,范围for循环此时也是可以实现的:
typedef T* iterator;
typedef const T* const_iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator beign()
{
return _start;
}
const_iterator end()
{
return _finish;
}
四、reserve和resize
- reserve
reserve最大问题是深拷贝,开辟新空间进行赋值的时候如果直接使用memcpy是浅拷贝。
void reserve(size_t n)
{
if (n > capacity())
{
int Oldsize = size();//size需要保存,方便更改_finsih
T* tmp = new T[n];
//为空不需要拷贝
if (_start)
{
for (size_t i = 0; i < Oldsize; ++i)
{
tmp[i] = _start[i];
}
}
_start = tmp;
_finish = _start + Oldsize;
_endofstarge = _start + n;
tmp = nullptr;
}
}
- size()要保存
因为size = _finish - _start,_start已经改变了。而_finish没有改变,那么size就是一个任意数了,不再是原来的size了,就需要在开始时候用Oldsize进行存储size
- 使用memcpy问题
memcpy拷贝数据是按字节来拷贝的属于浅拷贝,对于需要在堆开辟空间的自定义类型存在问题,多次释放同一块空间将导致程序崩溃
vector<vector<int>> vv; vector<int> v(4, 1); //复用push_back尾插 vv.push_back(v); vv.push_back(v); vv.push_back(v); vv.push_back(v); //需要扩容成2倍 vv.push_back(v); for (size_t i = 0; i < vv.size(); i++) { for (size_t j = 0; j < vv[i].size(); j++) { cout << vv[i][j] << " "; } cout << endl; }
- resize
用n个数据初始化vector,那么就要用n和size进行比对,分情况讨论:
1、当n大于当前的size时,将size扩大到n,扩大的数据为val,若val未给出,则默认为容器所存储类型的默认构造函数所构造出来的值。
2、当n小于当前的size时,将size缩小到n。
根据resize函数的规则,进入函数我们可以先判断所给n是否小于容器当前的size,若小于,则通过改变_finish的指向,直接将容器的size缩小到n即可,否则先判断该容器是否需要增容,然后再将扩大的数据赋值为val即可。
void resize(size_t n, const T& value = T())
{
if (n < size())
{
_finish = _start + n;
}