既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
迭代器是我们遍历容器的利器没在后面还会引入各种迭代器及其他作用
我们先来实现一个简单的迭代器
//迭代器一般实现为容器的嵌套类型
//将这个类插入到之前写好的vector容器中
class iterator
{
public:
friend class vector<T, Alloc>;//声明称友元类
iterator(vector<T,Alloc>\*pvec,T \*ptr = nullptr)
:\_pVec(pvec), \_ptr(ptr)
{
_pVec->_head._next = itb;
}
bool operator!=(const iterator &it)const
{
if (_pVec == nullptr || _pVec != it._pVec)
{
throw"iterator incompatable";
}
return _ptr != it._ptr;
}
void operator++()
{
if (_pVec == nullptr)
{
throw"iterator invalid";
}
_ptr++;
}
T& operator\*()
{
if (_pVec == nullptr)
{
throw"iterator invalid";
}
return \*_ptr;
}
const T& operator\*()const { return \*_ptr; }
private:
T \*_ptr;
vector<T, Alloc> \*_pVec;//声明指向哪个容器
};
iterator begin() { return iterator(this, _first); }
iterator end() { return iterator(this, _last); }
int main()
{
Test t1, t2, t3;
cout << "-------------------" << endl;
vector<Test>vec;
vec.push\_back(t1);
vec.push\_back(t2);
vec.push\_back(t3);
cout << "-------------------" << endl;
vec.pop\_back();
vector<int>a;
for (int i = 0;i < 20;++i)
{
a.push\_back(rand() % 100 + 1);
}
vector<int>::iterator it = a.begin();
for (;it != a.end();++it)
{
cout << \*it << " ";
}
return 0;
}
一、迭代器失效
当我们定义一种特殊的环境的时候,比如删除容器中所有元素,或者给容器添加几个连续的元素,当我们用for循环利用迭代器++进行删除/添加的时候,我们会发现程序异常中断了,因为我们第一次调用earse之后迭代器就失效了,对一个已经失效的迭代器进行++操作的时候,就会产生错误。但是我们在插入或者删除点进行it自减操作的时候仍然可以继续利用迭代器继续访问容器元素。
下面我们给出迭代器失效的规则:
当容器进行插入和删除的时候,从当前插入或者删除位置到容器末尾所有元素的迭代器全部失效。如果是插入引起的元素扩容,则所有元素迭代器全部失效。
二、迭代器失效的解决
以vector容器来举例吧,在easer或者insert之后函数都会返回一个指向插入点或者删除点的迭代器,用it对其进行接收
vector<int> vec;
for (int i = 0; i < 20; i++)
{
vec.push\_back(rand() % 100 + 1);
}
auto it = vec.begin();
while (it != vec.end())
{
if (\*it % 2 == 0)
{
it = vec.erase(it);//对迭代器进行更新
}
else
{
++it;
}
}
当我们运行上述代码的时候,可以正常的插入和删除
三、迭代器失效底层原理
在进行之前,我们要在原有代码的基础上加上一个成员变量vector<T, Alloc>* _pVec,表明当前迭代器迭代的是哪个对象,防止不同容器之间的迭代器进行比较(不同容器的迭代器之间是不可以进行比较的)
因此各个函数都要进行一下判断的改变
bool operator!=(const iterator& it)const
{
if (_pVec == nullptr || _pVec != it._pVec)
{
throw"ierator incompatable!";
return false;
}
return _ptr != it._ptr;
}
void operator++()
{
//检查迭代器的有效性
if (_pVec == nullptr)
{
throw"iterator invalid";
}
_ptr++;
}
T& operator\*()
{
//检查迭代器的有效性
if (_pVec == nullptr)
{
throw"iterator invalid";
}
return \*_ptr;
}
Iterator_Base结构
struct Iterator_Base
{
//用链表获取元素的迭代器
Iterator\_Base(iterator \*c = nullptr, Iterator_Base \*n = nullptr)
:\_cur(c), \_next(n) {}
iterator \*_cur;//指向迭代器的指针
Iterator_Base \*_next;//指向下一个Iterator\_Base节点的地址
};
构造函数如下:
iterator(vector<T,Alloc>\*pvec,T \*ptr = nullptr)
:\_pVec(pvec), \_ptr(ptr)
{
Iterator_Base \*itb = new Iterator\_Base(this, _pVec->_head._next);
_pVec->_head._next = itb;
}
verfiy函数(检查迭代器是否有效)
void verify(T \*first,T \*last)
{
Iterator_Base\* pre = &this->_head;
Iterator_Base\* it = this->_head._next;
while (it != nullptr)
{
if (it->_cur->_ptr >= first&& it->_cur->_ptr <= last)
{
//迭代器失效,把itreator持有的容器指针置nullptr
it->_cur->_pVec = nullptr;
//删除当前迭代器节点,继续判断后面的迭代器节点是否失效
pre->_next = it->_next;
delete it;
it = pre->_next;
}
else
{
pre = it;
it = it->_next;
}
完整代码如下
template<typename T>
struct Allocator
{
T\* allocate(size_t size)//内存开辟
{
set\_new\_handler(0);
return (T\*)malloc(sizeof(T)\*size);
}
void deallocate(void \*p)//内存释放
{
free(p);
}
void construct(T \*p, const T &val)//负责对象构造
{
new(p) T(val);//定位new
}
void destroy(T \*p)//负责对象析构
{
p->~T(); //~T()代表T类型的析构函数
}
};
template<typename T,typename Alloc = Allocator<T>>
class vector
{
public:
vector(int size = 10)
{
//需要把给内存开辟和对象构造分开处理
//\_first = new T[size];//new 即使没有赋值 也会开辟空间
_first = _allocator.allocate(size);
_last = _first;
_end = _first + size;
}
~vector()
{
//析构容器的有效元素,然后释放first指针指向的堆内存
//delete[]\_first;
for (T \* p= _first;p != _last; ++p)
{
_allocator.destroy(p);//把first指针指向的数组的有效元素进行析构操作
}
_allocator.deallocate(_first);//释放堆上的数组内存
_first = _last = _end = nullptr;
}
vector(const vector<T> &swq)
{
int size = swq._end - swq._first;
//\_first = new T[size];
_first = _allocator.allocate(size);
int len = swq._last - swq._first;
for (int i = 0;i < len;i++)
{
//\_first[i] = swq.\_first[i];
_allocator.construct(_first + i, swq._first[i]);
}
_last = _first + len;
_end = _first + size;
}
vector<T>& operator = (const vector<T> &swq)
{
if (this = &swq)
{
return \*this;
}
//delete[]\_first;
for (T \* p= _first;p != _last; ++p)
{
_allocator.destroy(p);//把first指针指向的数组的有效元素进行析构操作
}
![img](https://img-blog.csdnimg.cn/img_convert/ed8aac5d0b9f8e277ba736503785e7cb.png)
![img](https://img-blog.csdnimg.cn/img_convert/20a7882cfacdb0e316201aa78184fbe2.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**
效元素进行析构操作
}
[外链图片转存中...(img-DnlY3ks4-1715570125898)]
[外链图片转存中...(img-6AdimjAH-1715570125899)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**