- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章关于STL的erase()陷阱-迭代器失效问题的总结由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
下面材料整理自Internet&著作.
STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list、set、map)。在使用erase方法来删除元素时,需要注意一些问题.
1.list,set,map容器 。
在使用 list、set 或 map遍历删除某些元素时可以这样使用:
1.1 正确写法1 。
1
2
3
4
5
6
7
8
9
10
11
|
std::list<
int
> List;
std::list<
int
>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
if( WillDelete( *itList) )
{
itList = List.erase( itList);
}
else
itList++;
}
|
1.2 正确写法2 。
1
2
3
4
5
6
7
8
9
10
11
|
std::list<
int
> List;
std::list<
int
>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
if( WillDelete( *itList) )
{
List.erase( itList++);
}
else
itList++;
}
|
。
1.3 错误写法1 。
1
2
3
4
5
6
7
8
9
|
std::list<
int
> List;
std::list<
int
>::iterator itList;
for( itList = List.begin(); itList != List.end(); itList++)
{
if( WillDelete( *itList) )
{
List.erase( itList);
}
}
|
。
1.4 错误写法2 。
1
2
3
4
5
6
7
8
9
10
11
|
std::list<
int
> List;
std::list<
int
>::iterator itList;
for( itList = List.begin(); itList != List.end(); )
{
if( WillDelete( *itList) )
{
itList = List.erase( ++itList);
}
else
itList++;
}
|
1.5 分析 。
正确使用方法1:通过erase方法的返回值来获取下一个元素的位置 。
正确使用方法2:在调用erase方法之前先使用 “++”来获取下一个元素的位置 。
错误使用方法1:在调用erase方法之后使用“++”来获取下一个元素的位置,由于在调用erase方法以后,该元素的位置已经 。
被删除,如果在根据这个旧的位置来获取下一个位置,则会出现异常.
错误使用方法2:同上.
2. vector,deque容器 。
在使用 vector、deque遍历删除元素时,也可以通过erase的返回值来获取下一个元素的位置:
2.1 正确写法 。
1
2
3
4
5
6
7
8
9
10
11
|
std::vector<
int
> Vec;
std::vector<
int
>::iterator itVec;
for( itVec = Vec.begin(); itVec != Vec.end(); )
{
if( WillDelete( *itVec) )
{
itVec = Vec.erase( itVec);
}
else
itList++;
}
|
。
2.2 注意 。
注意:vector、deque 不能像上面的“正确使用方法2”的办法来遍历删除。原因请参考Effective STL条款9。摘录到下面:
1) 对于关联容器(如map, set, multimap,multiset),删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响.
1
2
3
4
5
6
7
8
|
for (iter = cont.begin(); it != cont.end();)
{
(*iter)->doSomething();
if (shouldDelete(*iter))
cont.erase(iter++);
else
++iter;
}
|
因为iter传给erase方法的是一个副本,iter++会指向下一个元素.
2) 对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。还好erase方法可以返回下一个有效的iterator.
1
2
3
4
5
6
7
8
|
for (iter = cont.begin(); iter != cont.end();)
{
(*it)->doSomething();
if (shouldDelete(*iter))
iter = cont.erase(iter);
else
++iter;
}
|
3)对于list来说,它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种方法都可以使用.
3.迭代器失效的情况 。
3.1 vector 。
内部数据结构:数组.
随机访问每个元素,所需要的时间为常量.
在末尾增加或删除元素所需时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化.
可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存.
vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同)。当把超过capacity()-size()个元素插入vector中时,内存会重新分配,所有的迭代器都将失效;否则,指向当前元素以后的任何元素的迭代器都将失效。当删除元素时,指向被删除元素以后的任何元素的迭代器都将失效.
3.2 deque 。
内部数据结构:数组.
随机访问每个元素,所需要的时间为常量.
在开头和末尾增加元素所需时间与元素数目无关,在中间增加或删除元素所需时间随元素数目呈线性变化.
可动态增加或减少元素,内存管理自动完成,不提供用于内存管理的成员函数.
增加任何元素都将使deque的迭代器失效。在deque的中间删除元素将使迭代器失效。在deque的头或尾删除元素时,只有指向该元素的迭代器失效.
3.3 list 。
内部数据结构:双向环状链表.
不能随机访问一个元素.
可双向遍历.
在开头、末尾和中间任何地方增加或删除元素所需时间都为常量.
可动态增加或减少元素,内存管理自动完成.
增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效.
3.4 slist 。
内部数据结构:单向链表.
不可双向遍历,只能从前到后地遍历.
其它的特性同list相似.
3.5 stack 。
适配器,它可以将任意类型的序列容器转换为一个堆栈,一般使用deque作为支持的序列容器.
元素只能后进先出(LIFO).
不能遍历整个stack.
3.6 queue 。
适配器,它可以将任意类型的序列容器转换为一个队列,一般使用deque作为支持的序列容器.
元素只能先进先出(FIFO).
不能遍历整个queue.
3.7 priority_queue 。
适配器,它可以将任意类型的序列容器转换为一个优先级队列,一般使用vector作为底层存储方式.
只能访问第一个元素,不能遍历整个priority_queue.
第一个元素始终是优先级最高的一个元素.
3.8 set 。
键和值相等.
键唯一.
元素默认按升序排列.
如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效.
3.9 multiset 。
键可以不唯一.
其它特点与set相同.
3.10 hash_set 。
与set相比较,它里面的元素不一定是经过排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然跟hash函数有关).
其它特点与set相同.
3.11 hash_multiset 。
键可以不唯一.
其它特点与hash_set相同.
3.12 map 。
键唯一.
元素默认按键的升序排列.
如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效.
3.13 multimap 。
键可以不唯一.
其它特点与map相同.
3.14 hash_map 。
与map相比较,它里面的元素不一定是按键值排序的,而是按照所用的hash函数分派的,它能提供更快的搜索速度(当然也跟hash函数有关).
其它特点与map相同.
3.15 hash_multimap 。
键可以不唯一.
其它特点与hash_map相同.
以上就是小编为大家带来的关于STL的erase()陷阱-迭代器失效问题的总结全部内容了,希望大家多多支持我~ 。
最后此篇关于关于STL的erase()陷阱-迭代器失效问题的总结的文章就讲到这里了,如果你想了解更多关于关于STL的erase()陷阱-迭代器失效问题的总结的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
正如问题所说,C++ 程序员在转向 Java 时面临哪些常见/主要问题?我正在寻找一些广泛的主题名称或示例以及工程师必须进行的日常调整。然后我可以去深入阅读这个。 我对多年来使用 C++ 并不得不使用
我们正在准备发布一个在过去一年中一直在开发的大型网络应用程序。我们即将开始集成 ActiveMerchant 的过程,以处理该服务的经常性订阅费用。 我正在寻找关于考虑到我们的要求(如下所列)的最佳实
您陷入过哪些 Powershell 陷阱? :-) 我的是: # ----------------------------------- function foo() { @("text")
对于商业数据库而言,数据库升级是一个优先级很高的事情,有版本升级路线图,有相应的补丁,而且对于方案还有一系列的演练,显然是一场硬仗。而在MySQL方向上,升级这件事情就被淡化了许多,好像只能证明它的
Android 新增了 AsyncLayoutInflater类到他们的支持库版本 24.0 和更高版本,并且可以在 Android SDK 4.0 或更高版本(几乎所有可用的设备)中使用。 根据 A
作为一名刚接触 Vala 的程序员,您对刚接触该语言的人的第一条建议是什么? 最佳答案 这很大程度上取决于您的背景。如果您来自 C/C++/Java,最好的建议是学习函数式编程。 Vala 支持真正的
作为 Spring 世界的新手,我认为如果有一个社区 Wiki 页面列出基于 Spring 的项目中常见的陷阱会很好。 这些包括: 被误解的概念 在 Spring 3.X 中不再推荐的 Spring
我正在开发一个脚本来管理一些陷阱。一开始我只用这段代码管理 INT 和 SIGTSTP,它工作得很好: #!/bin/bash function capture_traps() { echo
bash 中是否可以在函数退出时调用某些命令。我的意思是: function foo { # something like this maybe? trap "echo \"exit
我们在我们的域中托管了一个应用程序。所有用户都需要先通过 POST 表单登录。登录后,表单会自动重定向到我们网站上的仪表板页面。 是否可以允许一些客户托管他们自己的登录表单(在他们的网站上),然后发布
我有一个无窗口计时器(没有 WM_TIMER),它只在给定的时间段过去后触发一次回调函数。它作为 SetTimer()/KillTimer() 实现。时间段足够小:100-300 毫秒。 对于每个如此
我使用 Java 大约一个月了,总体而言仍然是编程方面的业余爱好者,所以如果我有什么不对的地方,请随时纠正我。也许我会提供一些多余的细节,但我现在很困惑,无法决定什么才是重要的。 因此,我一直在开发多
我正在开发一个需要使用 FileSystemWatcher 类的 C# 程序,以便在创建新文件时通知它。作为初始化的一部分,程序会扫描目录,以便处理其中已存在的任何文件。一切正常。 但是,在与另一位开
下面材料整理自Internet&著作。 STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list
我正在使用 NuGet 包 Polly实现捕获故障转移 SQL 异常的重试逻辑。我在 Azure 中设置了 SQL Server Always On 高可用性。 我不想捕获所有 SQL 异常(这是不正
在编写 Scala RemoteActor 代码时,我注意到了一些陷阱: 必须设置 RemoteActor.classLoader = getClass().getClassLoader() 以避免“
出于某种原因,当我针对不存在的文件运行以下脚本时,我的脚本没有捕获异常。我基于我在网上找到的示例中的代码,但它似乎对我不起作用。 我将不胜感激有关如何解决此问题的任何提示或指示。 注意:在下面的例子中
我正在尝试从 R 调用 winBUGS 来估计逻辑回归。我正在使用以下代码: # Directorio de trabajo setwd("~/3 Diplomado/7 Bayesiana/8t1"
我正在尝试从 R 调用 winBUGS 来估计逻辑回归。我正在使用以下代码: # Directorio de trabajo setwd("~/3 Diplomado/7 Bayesiana/8t1"
我正在使用 ctypes 包装一个大型 C 库。 ctypesgen生成了包装代码(与我自己的做法相差不远)。作为包装 C 结构的 ctypes 的一部分,它们被制作为对象,其中一些在 C 中具有“s
我是一名优秀的程序员,十分优秀!