首页 > 试题广场 >

会导致上面的代码片段崩溃的CONTAINER类型是?

[单选题]
CONTAINER::iterator iter, tempIt;
for (iter = cont.begin(); iter != cont.end();)      
{
    tempIt = iter;
    ++iter;
    cont.erase(tempIt);
      
}
假设cont是一个CONTAINER的实例,里面包含数个元素,那么当CONTAINER为:
1、vector   2、list   3、map    4、deque
会导致上面的代码片段崩溃的CONTAINER类型是?
  • 1,4
  • 2,3
  • 1,3
  • 2,4
答案A(1, 4)
解释:首先看看各个容器的erase(pos)实现吧:
1. vector,erase(pos),直接把pos+1到finish的数据拷贝到以pos为起点的区间上,也就是vector的长度会逐渐变短,同时iter会逐渐往后移动,直到iter == cont.end(),由于容器中end()返回的迭代器是最后一个元素的下一个(这个地方没有任何值),现在考虑这个状态前一个状态,此时要删除的点是iter, tempIt = iter, ++iter会指向此时的end(),但是执行erase(tempIt)之后,end()向前移动了!!!问题来了,此时iter空了!!!不崩溃才怪。

2. list,erase(pos),干的事情很简单,删除自己,前后的节点连接起来就完了,所以iter自增的过程不会指空,不会崩溃喽。

3. map,erase(pos),干的事情太复杂,但是我们需要知道的信息其实很少。该容器底层实现是RBTree,删除操作分了很多种情形来讨论的,目的是为了维持红黑树性质。但是我们需要知道的就是每个节点类似于list节点,都是单独分配的空间,所以删除一个节点并不会对其他迭代器产生影响,对应到题目中,不会崩溃喽。

4. deque,erase(pos),与vector的erase(pos)有些类似,基于结构的不同导致中间有些步骤不太一致。先说说deque的结构(这个结构本身比较复杂,拣重要说吧,具体看STL源码),它是一个双向开口的连续线性空间,实质是分段连续的,由中控器map维持其整体连续的假象。其实题中只要知道它是双向开口的就够了(可以在头部或尾部增加、删除)。在题中有erase(pos),deque是这样处理的:如果pos之前的元素个数比较少,那么把start到pos-1的数据移到起始地址为start+1的区间内;否则把pos后面的数据移到起始地址为pos的区间内。在题中iter一直往后移动,总会出现后面数据比前面少的时候,这时候问题就和1一样了,必须崩溃!

发表于 2015-07-15 20:34:39 回复(7)
关联容器(如map, set, multimap,multiset),删除当前的iterator,只会使当前的iterator失效,只要在erase时,递增当前iterator即可。
对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。不过erase方法可以返回下一个有效的iterator,cont.erase(iter++)可以修改为cont.erase(iter)
list使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator。
发表于 2015-07-15 11:49:53 回复(1)
A
1,4为线性存储结构,生成迭代器访问过程中不可删除item。
发表于 2015-07-17 12:40:49 回复(0)
考察知识点:迭代器失效
发表于 2017-08-17 22:18:22 回复(0)
容器选择一般遵循的原则:

1.如果需要高效的随即存取,而不在乎插入和删除的效率,一般使用vector
2、如果需要大量的插入和删除,而不关心随即存取,应用list
3、如果需要随即存取,而且关心两端数据的插入和删除,deque。

4、如果要存储一个数据字典,并要求方便地根据key找value,选择map

发表于 2016-06-26 16:09:12 回复(0)
可以改为iter = cont.erase(tmptIt);
发表于 2017-04-10 19:06:56 回复(0)
对于vector、deque容器来讲,会导致迭代器失效,即原迭代器是相当于一个野指针的状态
 vector迭代器的几种失效的情况: 1.当插入(push_back)一个元素后,end操作返回的迭代器肯定失效。 2.当插入(push_back)一个元素后,capacity返回值与没有插入元素之前相比有改变,则需要重新加载整个容器,此时first和end操作返回的迭代器都会失效。 3.当进行删除操作(erase,pop_back)后,指向删除点的迭代器全部失效;指向删除点后面的元素的迭代器也将全部失效。
在deque容器的任何其他位置的插入和删除操作将使指向该容器元素的所有迭代器失效
list的迭代器好像很少情况下会失效
发表于 2015-07-13 17:07:14 回复(1)
A顺序存放结构,删除时,迭代器失效,指向不可访问地址。
发表于 2015-07-15 16:42:05 回复(0)
第1个、第4个都是线性的类型存储,所以会存在崩溃
发表于 2014-10-25 00:26:19 回复(0)
操作前如下:
vector: 5 end
iter ---^
操作后如下:
vector: end unknown
iter -------^
操作非法!deque道理近似,故选A。
编辑于 2018-12-03 20:27:35 回复(0)
对于vector删除的正确做法:
CONTAINER::iterator iter , tempIt;
for(iter = cont.begin() ; iter != cont.end() ; )   
{
    iter = cont.erase(iter);        
}
原因是:erase操作后使得iter失效,iter++并不能指向下一个元素位置;而恰好erase返回了被删除元素的位置,且vector重新调整全部元素,被删除元素的后者填补了该位置,因此不需要iter++
发表于 2018-09-08 10:34:58 回复(0)
选A,因为vector和deque容器都会有连续的存储空间,当改变容器指针所指向的地址中的元素的时候,容器就会重新选择足够的地址空间,当前的迭代器就会失效,所以程序就会崩溃。
发表于 2023-12-25 15:15:59 回复(0)

画图秒懂!

vector、deque 存储元素个数为奇数时:
图片说明
vector、deque 存储元素个数为偶数时:
图片说明
list、map存储元素(奇偶情况相同):
图片说明

编辑于 2023-12-05 10:39:08 回复(0)
3,map其实也会发生崩溃,因为当执行erase删除当前的ite时,当前的ite失效,再执行ite++程序崩溃。可以改成erase(ite++);这条语句分三步:将ite值传给erase,ite++,执行erase(ite)ite失效。所以在ite失效之前已将ite指向下一节点,避免了因ite失效导致的程序崩溃
发表于 2020-04-22 14:41:13 回复(0)
1,4为线性存储结构,生成迭代器访问过程中不可删除item。
发表于 2018-02-03 09:15:52 回复(0)
注意这种题
发表于 2017-01-05 21:33:02 回复(0)
关键是erase会自己把链表结构的集合中,去掉的元素2边连起来,我还以为是只有顺序才能用遍历器呢,其实都可以的,只是只有链表结构的能删除,线性结构的集合不能随意删除元素。
发表于 2016-11-14 23:18:30 回复(0)
list和map都是关联容器,删掉的地址都会失效。iter会逐个遍历到end处
发表于 2016-08-14 21:42:52 回复(0)
1,4两者是线性存储结构,
发表于 2016-05-19 14:59:15 回复(0)
选A,因为vector和deque容器都会有连续的存储空间,当改变容器指针所指向的地址中的元素的时候,容器就会重新选择足够的地址空间,当前的迭代器就会失效,所以程序就会崩溃。
发表于 2015-07-15 22:08:59 回复(0)