目录
一、各种函数接口
vector对象的构造方式
2、空间增长问题
resize
可以看到,resize不仅会改变size的大小,还会去开辟空间
reserve
reverse只是改变capacity的大小,不回去影响size的大小
3、vector的增删查改
push_back&pop_back
要注意的是,vector并没有自带头插和头删,因为是数组空间,头部操作效率不高
find()
这是一个算法函数
operator[]
这是一个运算符重载,使用这个方法可以类似于数组一样来操作
二、vector迭代器失效问题
void main()
{
vector<int> v = { 1 };
auto it = v.begin();
cout << *it << endl;
v.push_back(2);
cout << *it << endl;
}
这端代码一运行就会报错
就是因为空间发生了变化
一、push_back
这段代码一运行就会报错
这是因为在进行插入操作的时候,因为vector的底层是一块连续的空间,在扩容的时候是会去申请出来一块连续的新空间,
这个时候只是只是start和finish进行了更新,迭代器并没有进行更新。
只要空间发生变化,就一定会导致迭代器失效
二、erase
这个时候在vs2019是编译不通过的(vc6.0是可以通过编译的),这是因为系统并不知道删除的是哪个位置的数据,假如是中间数据,那么后面数据前移,
it3原来的空间还是有效的,只是数据变了,
但如果是删除最后一个数据,那么it3所指向的空间就没有数据了,这时候就是明显的错误,会引发异常
解决办法:对迭代器重新赋值
还要一个例子:
这段代码就是有了明显的错位,都已经erase(it)了,还进行++it,那肯定是错误的
应该用 it=v.erase(it)
正确代码:
vector的浅拷贝问题(内存拷贝)
我们之前在把旧空间的数据拷贝到新空间的时候,使用的是memcpy函数进行的浅拷贝,
这时候在遇到string类型的时候就有可能会发生问题,(double free)会引发异常,要想真正处理好,需要使用深拷贝
先写一下拷贝构造的代码
写一个for循环
这个问题和之前的深赋值问题类似
三、vector的模拟实现
#pragma once
namespace bit
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
public:
// Vector的迭代器是一个原生指针
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator cbegin()
{
return _start;
}
const_iterator cend() const
{
return _finish;
}
// construct and destroy
//构造函数
vector():_start(nullptr),_finish(nullptr), _endOfStorage(nullptr)
{}
vector(int n, const T& value = T())
{}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
reserve(last - first);
while (first != last)
{
push_back(*first);
++first;
}
}
vector(const vector<T>& v):_start(nullptr),_finish(nullptr), _endOfStorage(nullptr)
{}
vector<T>& operator= (vector<T> v)
{
}
~vector()
{}
// capacity
size_t size() const
{
return _finish- _start;
}
size_t capacity() const
{
return _endOfStorage - _start;
}
//扩容函数
void reserve(size_t n)
{
if (n >capacity())//先判断需不需要进行扩容
{
//申请新空间
iterator new_start = new T[n];
//拷贝原来的数据
size_t old_size = size();
memcpy(new_start, _start, sizeof(T) * old_size);
//释放原来的空间
delete[]_start;
//更新数组
_start = new_start;
_finish = _start + old_size;
_endOfStorage = _start + n;
}
}
void resize(size_t n, const T& value = T())
{
if (n < size())
{
_finish = _start + n;
return;
}
if (capacity() < n)//这时候需要去扩容
{
reserve(n);
}
//填充操作
int offset = n - size();
for (int i = 0; i < offset; ++i)
{
*_finish++ = value;
}
}
///access///
T& operator[](size_t pos)
{
return _start[pos];
}
const T& operator[](size_t pos)const
{
return _start[pos];
}
///modify/
void push_back(const T& x)
{
insert(end(), x);
}
void pop_back()
{
erase(end());
}
void swap(vector<T>& v)
{
}
iterator insert(iterator pos, const T& x)
{
if (size() >= capacity())//这个时候就需要去扩容了
{
size_t offset = pos - _start;//先计算pos的位置,防止迭代器失效
size_t old_capacity = capacity();
size_t new_capacity = (old_capacity == 0 ? 1 : old_capacity * 2);
reserve(new_capacity);
//这时候记得还要调整pos的位置
pos = _start + offset;
}
iterator temp = _finish++;//使用临时变量
while (temp != pos)
{
*temp = *(temp - 1);
--temp;
}
*pos = x;
return pos;
}
iterator erase(iterator pos)
{
iterator temp = pos++;
for (int i = 0; i < _finish - pos; ++i)
{
*temp = *(temp + 1);
++temp;
}
--_finish;
return pos;
}
private:
iterator _start; // 指向数据块的开始
iterator _finish; // 指向有效数据的尾
iterator _endOfStorage; // 指向存储容量的尾
};
}
STL的概念图