当前位置: 首页 > wzjs >正文

做网站哪里的服务器速度快深圳网站推广

做网站哪里的服务器速度快,深圳网站推广,embed wordpress,vancl凡客诚品正品目录 1.vector::insert函数 1.1问题分析 1.2vector::insert函数的最终实现 1.3vector::insert函数的分析 2.第二种迭代器失效 3.第三种迭代器失效 4.迭代器失效deepseek的回答 1. 迭代器失效的原因 2. 不同容器的迭代器失效情况 (1)std::vecto…

目录

1.vector::insert函数

1.1问题分析

1.2vector::insert函数的最终实现

1.3vector::insert函数的分析

2.第二种迭代器失效

3.第三种迭代器失效

4.迭代器失效deepseek的回答

1. 迭代器失效的原因

2. 不同容器的迭代器失效情况

(1)std::vector

(2)std::deque

(3)std::list / std::forward_list

(4)std::map / std::set(及 unordered_ 版本)

3. 如何避免迭代器失效?

(1)更新迭代器

(2)使用索引替代迭代器

(3)先收集再删除

(4)谨慎使用 reserve / rehash

4. 总结

5.总结


1.vector::insert函数

我们测试一下这个函数:

void func(const td::vector<int>& v)
{for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
void test()
{vector<int> v1; v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);func(v1);v1.insert(v1.begin(), 10);func(v1);v1.erase(v1.begin() + 3);func(v1);
}

那么运行结果为:

如果我们把代码改为如下形式:

void test()
{vector<int> v1; v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);func(v1);v1.insert(v1.begin(), 10);func(v1);v1.erase(v1.begin() + 3);func(v1);
}

则运行结果为:

也就是说insert函数是一定有问题的,这个需要我们调试分析一下代码:

1.1问题分析

我们发现在经过这个reserve后_start地址改变了,而这个pos地址不变,也就是说pos指向旧空间,但reserve函数在调用时会释放旧空间,it是_finish-1,而pos还是旧空间,在循环时一直判断it>=pos,那么就不会结束,会造成越界。

这种情况就是迭代器失效,pos指向旧空间,但扩容导致迭代器失效,本质上就是野指针了。

所以我们应该这样写:

1.2vector::insert函数的最终实现

//insert函数的实现2
void insert(iterator pos, const T& x)
{//判断是否合法assert(pos >= _start);assert(pos <= _finish);//判满if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator it = _finish - 1;//移动数据while (it >= pos){*(it + 1) = *it;--it;}*pos = x;++_finish;
}

1.3vector::insert函数的分析

这是一个比较浅的迭代器失效的问题,但是这里也提醒我们了一个很重要的点:需要注意函数调用后可能会导致迭代器失效的问题。

2.第二种迭代器失效

我们看如下代码:

void test()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);int i;cin >> i;auto it = v1.begin() + 1;v1.insert(it, 10);cout << *it << endl;
}

那么运行结果为:

不管我们输入0-3中的任意数字,最终打印结果一定不是最终值,这是因为再进行插入,那么最终会导致扩容,而扩容导致原地址失效,导致it为野指针,这个it的类型可以写为:td::vector<int>::iterator,所以导致了打印结果不正确。且insert是否扩容是不确定的,无法判断是否有迭代器失效。

那如果我们把insert改为如下定义:

void insert(iterator& pos, const T& x)
{//判断是否合法assert(pos >= _start);assert(pos <= _finish);//判满if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator it = _finish - 1;//移动数据while (it >= pos){*(it + 1) = *it;--it;}*pos = x;++_finish;
}

也就是说我们把第一个形参改为引用,这样就可以了吗?

用如下函数测试:

void test()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);int i;cin >> i;auto it = v1.begin() + 1;//不行v1.insert(it + 1, 10);//不行v1.insert(v1.begin(), 10);cout << *it << endl;
}

那么会有两个报错:

所以我们不能这样写!

所以我们最终解决办法就只能是再创建一个迭代器,否则很容易出错!

3.第三种迭代器失效

int main()
{std::vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);auto it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){v1.erase(it);}++it;}for (const auto& e : v1){cout << e << " ";}cout << endl;return 0;
}

那么运行结果为:

首先声明一下:这里的是库里面的函数,而且如果测试都是没有其他问题的,但是如果你打印也会有问题。

为什么用erase也会失效?

首先我们若遇到偶数,判断出2为偶数,但是v1会直接跳过3的位置去判断下一个位置了,所以会导致结果不准确,然后最终非法访问?

那么我们改代码为如下形式:

int main()
{std::vector<int>v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);auto it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){v1.erase(it);}else{++it;}}for (const auto& e : v1){cout << e << " ";}cout << endl;return 0;
}

为什么还是会有问题(这个取决于编译器,在g++下是运行正确的)?

这个取决于编译器,VS会认为erase、insert后的迭代器是失效的。可以任务迭代器有个标记,在经过这些过程后会改变标记,因为这是一个更加严格的检查!而在不同的编译器可能运行结果是不同的,所以我们在之后的学习中要把一段程序在多个编译器运行,保证它在每个编译器都能运行

但是也要注意:erase在多数编译器中会只挪动数据,但有些编译器可能为了节省空间而缩容,所以单单erase也可能导致野指针!

结论:erase(it)以后,不同平台实现有差异,但是我们统一认为it失效了!我们在用完了一个后需要进行迭代器的更新!

4.迭代器失效deepseek的回答

通过deepseek我们可以更加深入的了解迭代器失效的问题,也方便了我们之后避免此类问题。以下是deepseek的搜索结果:

在 C++ 中,迭代器(iterator) 是指向容器(如 vectorlistmap 等)元素的抽象指针。但某些操作会导致迭代器失效(invalidated),即它不再指向有效的元素,继续使用会导致未定义行为(UB),如程序崩溃或数据错误。


1. 迭代器失效的原因

迭代器失效通常发生在容器结构被修改时,例如:

  • 插入元素insertpush_backemplace 等)

  • 删除元素erasepop_backclear 等)

  • 容器扩容(如 vector 的 reserve 或自动增长)

失效的根本原因是:

  • 内存重新分配(如 vector 扩容,旧迭代器指向被释放的内存)

  • 元素位置移动(如 vector 插入/删除导致后续元素位移)

  • 数据结构变化(如 unordered_map 的 rehash)


2. 不同容器的迭代器失效情况

不同容器对迭代器失效的敏感程度不同:

(1)std::vector

操作迭代器失效情况
push_back / emplace_back可能失效(如果触发扩容,所有迭代器失效;否则仅 end() 失效)
insert / emplace可能失效(插入点及之后的迭代器失效,如果扩容则全部失效)
erase被删元素及之后的迭代器失效
pop_back仅 end() 失效
clear / resize所有迭代器失效
reserve不影响现有迭代器(除非 capacity 改变)

示例:

std::vector<int> v = {1, 2, 3};
auto it = v.begin() + 1; // 指向 2
v.push_back(4);          // 可能扩容,it 失效!
// std::cout << *it;     // 未定义行为(UB)!

(2)std::deque

操作迭代器失效情况
push_back / push_front通常不影响现有迭代器(除非重新分配)
insert / emplace所有迭代器失效
erase被删元素及之后的迭代器失效
pop_back / pop_front仅被删元素的迭代器失效
clear所有迭代器失效

特点

  • deque 是分段连续存储,头尾插入通常不影响中间迭代器。

  • 但 insert 可能导致所有迭代器失效(因为可能重新分配)。


(3)std::list / std::forward_list

操作迭代器失效情况
push_back / push_front不影响现有迭代器
insert / emplace不影响其他迭代器
erase仅被删元素的迭代器失效
pop_back / pop_front仅被删元素的迭代器失效
clear所有迭代器失效

特点

  • list 是双向链表forward_list 是单向链表

  • 插入/删除只影响当前节点,其他迭代器仍然有效。

示例:

std::list<int> l = {1, 2, 3};
auto it = ++l.begin(); // 指向 2
l.erase(it);           // it 失效,但其他迭代器仍然有效

(4)std::map / std::set(及 unordered_ 版本)

操作迭代器失效情况
insert / emplace不影响现有迭代器
erase仅被删元素的迭代器失效
clear所有迭代器失效

特点

  • 基于红黑树map/set)或哈希表unordered_map/unordered_set)。

  • 插入/删除通常不影响其他迭代器(除非 rehash,如 unordered_map 扩容)。

unordered_map 的 rehash 问题:

std::unordered_map<int, int> m;
auto it = m.begin();
m.reserve(1000); // 可能触发 rehash,it 失效!
// std::cout << it->first; // UB!

3. 如何避免迭代器失效?

(1)更新迭代器

某些操作(如 erase)会返回新的有效迭代器

std::vector<int> v = {1, 2, 3};
auto it = v.begin() + 1;
it = v.erase(it); // it 现在指向 3(原 2 被删)

(2)使用索引替代迭代器

vector 可以用 [] 或 at() 访问:

std::vector<int> v = {1, 2, 3};
size_t idx = 1;
v.erase(v.begin() + idx); // 用索引计算新迭代器

(3)先收集再删除

避免在循环中直接删除:

std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> to_remove = {2, 4};
for (auto val : to_remove) {v.erase(std::remove(v.begin(), v.end(), val), v.end());
}

(4)谨慎使用 reserve / rehash

vector / unordered_map 扩容会导致所有迭代器失效

std::vector<int> v = {1, 2, 3};
auto it = v.begin();
v.reserve(100); // 可能扩容,it 失效!

4. 总结

容器插入操作删除操作扩容/rehash
vector可能失效可能失效全部失效
deque通常安全部分失效可能失效
list安全仅当前失效不适用
map/set安全仅当前失效不适用
unordered_map安全仅当前失效全部失效(rehash)

最佳实践:

  • vector:小心 push_back / insert / erase,尽量用索引。

  • list / map:插入/删除较安全,但 erase 后别用旧迭代器。

  • unordered_map:注意 reserve / rehash 导致失效。

理解迭代器失效机制,能避免很多隐藏的 UB(未定义行为)问题!

5.总结

这讲内容比较简单,但是还是说明我们也需要进行判断自己的迭代器是否会失效,这也是比较重要的知识。

下节将继续讲解vector的模拟实现的内容。好了,这讲结束了,喜欢的可以一键三连哦!下节再见!

http://www.dtcms.com/wzjs/485808.html

相关文章:

  • 做公司网站需要几天今日最新国际新闻
  • 阿里云免费空间宁波专业seo服务
  • 女人与马做受网站帮别人推广app赚钱
  • 做网站如何收益zac博客seo
  • 网站建设 哪家好重庆seo网页优化
  • 营销型网站网站bt兔子磁力天堂
  • 网站建设去哪北京seo顾问服务公司
  • 如何做网站ppt网络营销课程个人感悟
  • 学产品设计好找工作吗谷歌seo 优化
  • 做网站和优化品牌营销案例分析
  • 个人备案可以做影视网站吗永久不收费免费的软件
  • 做网站视频 上传到哪儿互联网营销师培训
  • 在线建站|网页制作|网站建设平台网络营销swot分析
  • 怎样 建设电子商务网站整站seo技术
  • ui培训讲师优化设计答案五年级下册
  • 谁家做网站广州最新发布最新
  • 网站开发三层架构排位及资讯
  • 北京电脑培训网站中国职业培训在线
  • 网站快速排名技巧如何建立网站 个人
  • 我想做一个小网站搞页游该怎么做企业网站seo公司
  • 网站建设需要钱吗三叶草gw9356
  • 维护网站费用南京最新消息今天
  • 做网站挂靠服务器什么好发软文的平台
  • 网站建设1app优化推广
  • 有什么超好用的做简历的网站品牌推广公司
  • 商城小程序开发费用唐山seo排名
  • 唐山网站建设最好的百度广告开户流程
  • 网站上做的vi设计是怎么做的营销推广工作内容
  • 沧州哪家做网站好全网营销国际系统
  • 网站建设调研报告的前言搜索指数在线查询