博主主页:LiUEEEEE
C++专栏
C语言专栏
数据结构专栏
排序算法专栏
力扣牛客经典题目专栏
1、了解迭代器是什么
-
迭代器不是指针,是类模板,表现的像指针。他只是模拟了指针的一些功能,通过重载了指针的一些操作符,->,*,++ --等封装了指针,是一个“可遍历STL( Standard Template Library)容器内全部或部分元素”的对象, 本质是封装了原生指针,他可以根据不同类型的数据结构来实现不同的++,–,*等操作;
-
迭代器只能指向容器,而指针还可以指向函数,
-
迭代器返回的是对象引用而不是对象的值,所以cout只能输出迭代器使用*取值后的值而不能直接输出其自身。
下面是通过对迭代器类型名称的打印所呈现的迭代器类型,由此可见,迭代器并非传统意义上的指针,而是与指针有类似功能的工具。
2、迭代器失效是指什么
迭代器失效是指迭代器所指向的空间被销毁了,而我们重新使用这个指向被销毁空间的迭代器时会发生非法访问,所以编译器会对非法使用的迭代器进行报错处理。
3、迭代器为何会失效
通过C++中 vector 和 string 类的学习可知,当我们对实例化的 vector 或 string 类对象进行数据插入时,如果发生了空间扩容,就会导致迭代器失效,其本质是,在扩容时,编译器会重新开辟一段已经扩容后的空间,并将原空间数据拷贝至新空间,而后将旧空间销毁,而此时迭代器所指向的依旧为旧空间的位置,所以会发生迭代器失效,此扩容过程类似于C语言中的realloc函数。
迭代器失效过程如下示意图(此示意图是以通过迭代器对原vector空间第5个位置进行数据插入,当数据个数大于4时会发生扩容)
而扩容结束后,再通过原本的迭代器进行操作时,就会发生非法访问,因为它指向的并不是新空间。
C++中迭代器失效并不只发生在空间扩容的过程中,在不同编译器下,如果编译器在删除数据时,发生了缩容,那么也有可能发生迭代器失效,因为此情况的发生依据编译器的不同,故为了方便起见,C++委员会默认在删除数据时迭代器也会发生失效,所以当使用者删除数据后再使用迭代器访问,即使没有发生失效状况,也会报错。
4、在模拟实现vector或string时如何防止迭代器失效
本篇以模拟实现vector为例,最好的防止措施就是提前备份好迭代器与起始位置的偏差值,在发生扩容后将迭代器更新,具体操作如下
//扩容
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size();
T* tmp = new T[n];
if(_start)
{
for (size_t i = 0; i < old_size; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + old_size;
_end_of_storage = _start + n;
}
}
本篇只展示了在扩容过程中的防治措施,如读者需要,可在自己实现的函数中自行更新。
5、模拟实现vector
以下是vector的模拟实现代码,如有需要可自取进行测试。
#include <assert.h>
namespace LY
{
template<class T>
class vector
{
public:
//可读可写迭代器
typedef T* iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
//只读迭代器
typedef const T* const_iterator;
const_iterator begin()const
{
return _start;
}
const_iterator end()const
{
return _finish;
}
//强制生成默认构造
vector() = default;
//拷贝构造函数
vector(const vector<T>& v)
{
reserve(v.capacity());
for (auto e : v)
{
push_back(e);
}
}
//构造函数 初始化n个val
vector(size_t n, const T& val = T())
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
vector(int n, const T& val = T())
{
reserve(n);
for (int i = 0; i < n; i++)
{
push_back(val);
}
}
//构造函数 初始化数据
vector(initializer_list<T> il)
{
reserve(il.size());
for (auto e : il)
{
push_back(e);
}
}
//迭代器区间初始化
template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
//数据个数
size_t size()const
{
return _finish - _start;
}
//空间个数
size_t capacity()const
{
return _end_of_storage - _start;
}
//析构函数
~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
//扩容
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size();
T* tmp = new T[n];
if(_start)
{
for (size_t i = 0; i < old_size; i++)
{
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + old_size;
_end_of_storage = _start + n;
}
}
//尾插数据
void push_back(const T& x)
{
//if (_finish == _end_of_storage)
//{
// size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
// reserve(newcapacity);
//}
//*_finish++ = x;
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 pop_back()
{
assert(_finish != _start);
_finish--;
}
//指定位置插入数据
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);
if (_finish == _end_of_storage)
{
size_t len = pos - _start;
size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
reserve(newcapacity);
pos = _start + len;
}
iterator end = _finish;
while (end != pos)
{
*end = *(end - 1);
--end;
}
*pos = x;
++_finish;
return pos;
}
//交换内容
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
//指定位置删除数据
void erase(iterator pos)
{
assert(pos <= _finish);
assert(pos >= _start);
iterator end = pos;
while (end != _finish - 1)
{
*end = *(end + 1);
++end;
}
_finish--;
}
//运算符重载 =
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
};
}
6、结语
十分感谢您观看我的原创文章。
本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
如需引用,注明地址。