vector是一个顺序表,它支持任意类型的数据,因此需要用到模板。要注意迭代器可能失效的问题。
目录
一、迭代器
template<class T> //类模板
typedef T* iterator;
typedef const T* const_iterator;
//迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
iterator begin() const
{
return _start;
}
iterator end() const
{
return _finish;
}
//迭代器初始化
template<class Inputiterator>
vector(Inputiterator first, Inputiterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
vector它的迭代器是一个指针。
迭代器初始化就是用一段迭代器区间去初始化, 也就是说可以用任意的迭代器区间去初始化它。
二、成员
private:
iterator _start = nullptr;//指向数据起始位置
iterator _finish = nullptr;//指向有效数据的尾
iterator _endOfStorage = nullptr;//指向有效空间的尾
它的成员是三个指针,我们可以直接给上缺省值nullptr,这样构造函数会写起来很方便。当然在这个地方也可以用两个整形,_size和_capactiy。
_finish - _start就是当前数据个数,_enOfStorage - _start就是当前容量大小。
三、构造函数
//构造n个空间,并填值
vector(size_t n,const T& val = T())
{
resize(n, val);
}
vector(int n, const T& val = T())
{
resize(n, val);
}
//默认构造
vector()
{}
在这个地方构造函数可以不用写初始化列表,C++11打了补丁,成员给缺省值,初始化的时候会按照成员缺省值初始化。这个地方主要看一下第一个构造函数,这个构造函数和resize的功能一样,我们直接调用resize来完成构造即可。要注意val的缺省值是一个匿名对象,如果是自定义类型会去调用自定义类型的构造函数来做缺省值,如果是内置类型也会调用内置类型的构造函数。内置类型也是可以用构造函数初始化的。
四、拷贝构造
//拷贝构造
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
_start = new T[v.capacity()];
//memcpy(_start, v._start, sizeof(T) * v.size());
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_endOfStorage = _start + v.capacity();
}
//复用
vector(const vector<T>& v)
{
reserve(v.size());
for (size_t i = 0; i < v.size(); i++)
{
push_back(v._start[i]);
}
}
这个地方拷贝构造可以复用reserve,直接开好要空间,再将值尾插进去即可。
也可以自己手写,这里要把成员全部处理一下,处理为nullptr,然后这个地方要注意的是拷贝数据不能用memcpy,否则如果vector内的数据是自定义类型就会出事。下面reserve会说。
五、析构函数
//析构
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _endOfStorage = nullptr;
}
}
六、交换
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
用库里的swap直接交换即可。
七、运算符重载
1、[ ]运算符重载
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
2、赋值运算符重载
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
这个地方直接用swap即可。注意传参的时候不要用引用。
八、容量
1、扩容不填数据reserve
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
//这个地方如果是自定义类型,调用自定义类型的赋值重载
//如果是内置类型这样也没问题
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endOfStorage = _start + n;
}
}
在这个地方要注意 要先把size(),保存起来,不然扩容之后,_start指向的是新的空间,而_finish指向的还是旧空间,这样size()的结果就是不正确的。为什么这个地方不能用memcpy呢?看下面的代码
void test_vector5()
{
vector<string>v1;
v1.push_back("11111");
v1.push_back("22222");
v1.push_back("33333");
v1.push_back("44444");
v1.push_back("55555");
}
下面的代码每一个都是自定义类型,如果reserve用的是memcpy会出什么问题?
就会出现上面的情况。也就是说vector是深拷贝,但是vector空间上存的对象是string的数组,memcpy就会导致string的对象浅拷贝。因此我们只能用上面的写法,上面的写法对自定义类型会调用它的赋值运算符重载,内置类型也没毛病。
2、扩容填数据resize
//扩容
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++;
}
}
}
在这个地方如果n大于数据个数,直接reserve一下,然后填数据即可。
3、当前数据个数
size_t size()const
{
return _finish - _start;
}
4、当前容量个数
size_t capacity()const
{
return _endOfStorage - _start;
}
九、插入删除
1、某个位置插入
void insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
//扩容后pos有可能失效,因此计算相对位置。
if (_finish == _endOfStorage)
{
size_t len = pos - _start;
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
reserve(newcapacity);
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
end--;
}
*pos = x;
_finish++;
}
这个地方要注意,扩容以后pos有可能失效,因此要先计算出pos和_start的面对位置,扩容之后再把pos更新。
因为扩容不一定是原地扩容,异地扩容的话_start就变了,pos还是原来的_start,那么它就失效了,因此要更新它。
2、某个位置删除
iterator erase(iterator pos)
{
assert(pos >= _start && pos <= _finish);
iterator it = pos;
while (it<= _finish)
{
*it = *(it + 1);
it++;
}
_finish--;
return pos;
}
这个地方注意pos是迭代器位置,先判断pos合法性,然后直接覆盖即可,这里要返回pos位置的下一个数据的迭代器,也就是pos。
3、尾插
void push_back(const T& x)
{
//自己写
/*if (_finish == _endOfStorage)
{
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
reserve(newcapacity);
}
*_finish = x;
_finish++;*/
//复用
insert(end(), x);
}
尾插可以直接写也可以直接复用insert。
十、完整代码
#include<iostream>
#include<assert.h>
using namespace std;
namespace vae
{
template<class T> //类模板
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
//迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
iterator begin() const
{
return _start;
}
iterator end() const
{
return _finish;
}
//构造
//迭代器初始化
template<class Inputiterator>
vector(Inputiterator first, Inputiterator last)
{
while (first != last)
{
push_back(*first);
first++;
}
}
vector(size_t n,const T& val = T())
{
resize(n, val);
}
vector(int n, const T& val = T())
{
resize(n, val);
}
vector()
{}
//拷贝构造
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
_start = new T[v.capacity()];
//memcpy(_start, v._start, sizeof(T) * v.size());
for (size_t i = 0; i < v.size(); i++)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_endOfStorage = _start + v.capacity();
}
/*vector(const vector<T>& v)
{
reserve(v.size());
for (size_t i = 0; i < v.size(); i++)
{
push_back(v._start[i]);
}
}*/
//析构
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _endOfStorage;
}
}
//扩容
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++;
}
}
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
for (size_t i = 0; i < sz; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endOfStorage = _start + n;
}
}
void push_back(const T& x)
{
/*if (_finish == _endOfStorage)
{
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
reserve(newcapacity);
}
*_finish = x;
_finish++;*/
insert(end(), x);
}
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
void insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
//扩容后pos有可能失效,因此计算相对位置。
if (_finish == _endOfStorage)
{
size_t len = pos - _start;
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
reserve(newcapacity);
pos = _start + len;
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
end--;
}
*pos = x;
_finish++;
}
iterator erase(iterator pos)
{
assert(pos >= _start && pos <= _finish);
iterator it = pos;
while (it<= _finish)
{
*it = *(it + 1);
it++;
}
_finish--;
return pos;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
size_t size()const
{
return _finish - _start;
}
size_t capacity()const
{
return _endOfStorage - _start;
}
private:
iterator _start = nullptr;//指向数据起始位置
iterator _finish = nullptr;//指向有效数据的尾
iterator _endOfStorage = nullptr;//指向有效空间的尾
};
void test_vector1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//v1.push_back(5);
//mrl::vector<int> v2(v1);
//for (auto& e : v1)
//{
// e += 1;
//}
v1.insert(v1.begin(), 100);
vector<int>::iterator p = v1.begin() + 3;
//这个地方要注意,迭代器有可能失效(扩容)!!
//insert之后就不能使用这个形参迭代器,因为它可能失效了
v1.insert(p, 20);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector2()
{
vector<int>v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
vector<int>v2(v1);
v1.insert(v1.end(),100);
v1.swap(v2);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
for (auto e : v2)
{
cout << e << " ";
}
cout << endl;
}
void test_vector3()
{
vector<int>v1;
v1.push_back(2);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
auto it = v1.begin();
while (it != v1.end())
{
if (*it % 2 == 0)
{
it = v1.erase(it);
}
else
{
++it;
}
}
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
void test_vector4()
{
vector<int>v1;
v1.resize(10, 0);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
vector<int>v2;
v2 = v1;
for (auto e : v2)
{
cout << e << " ";
}
}
void test_vector5()
{
vector<string>v1;
v1.push_back("11111");
v1.push_back("22222");
v1.push_back("33333");
v1.push_back("44444");
v1.push_back("55555");
vector<string>v2(v1);
for (auto& e : v1)
{
cout << e << " ";
}
cout << endl;
for (auto& e : v2)
{
cout << e << " ";
}
cout << endl;
}
void test_vector6()
{
vector<int>v1(10, 1);
for (auto& e : v1)
{
cout << e << " ";
}
cout << endl;
}
}
int main()
{
// mrl::test_vector1();
vae::test_vector6();
return 0;
}