泛型编程与STL--各类容器迭代器失效的场景

各类容器迭代器失效的场景:

其实在定义迭代器失效的时:在某些操作完成以后,认为这个迭代器指向的值有变化或者迭代器直接指向不合法的空间,都认为迭代器失效。只要不是指向操作之前的值都认为迭代器失效。

当要将元素安插于vector内,大小与容量之间的差别就变得格外重要。如果vector的大小等于其容量,安插新元素的唯一方法就是增加这个vector的内存总量,这意味得分配一块新的而且更大的内存,再将旧内存块的内容复制到新内存块中,然后归还旧内存块。

一旦vector的内存重新分配,其iterators便失效了。此外,在vector中间安插或删除元素,也会指向该安插点或删除点之后元素的所有iterators都失效。这表示如果你以member function reserve来原先分配内存,或如果所有安插或删除动作都在vector尾端进行,那么你就可以使vector的iterator不失效。

同时在vector内部是有复制构造函数和赋值构造函数的。

Vector<int>   test_ww(vecc); //使用的是copy构造函数

Vector<int>   test_ww;

Test_ww =vecc;//调用的是赋值构造函数

对于list来说:

是一个双向链表,能以O(1)时间在list开头、尾端、中间处安插及移除元素。List有一个重要心智,安插于结合(splice)动作不会造成指向list的iterators失效,即使是删除动作,也只会令指向被删除元素的那个iterator失效。这些iterators的顺序可能会被改变(也就是说在链表操作之后,一个list<T>::iterator可能拥有不同的前承元素与后继元素),但iterators自身不会被无效化或因此指向不同元素,除非明白执行无效化动作或目标物变换动作。

假设i是型别为vector<T>::iterator的一个有效iterator,当我们在i之前一个位置安插或移除一个元素,i会因此指向不同的元素,或者i根本完全失效。另一方面,假设i和j都是指向vector的iterators,存在某个整数n,使得I == j+n.这个情况下即使元素被安插在vector之中且i和j指向不同元素,两个指针的相互关系仍然维持不变。List正好相反,其iterators不会被无效化,也不会指向不同元素,但iterators的前承元素与后继元素的关系不会维持不变。

Deque使用说明:

Deque类似vector,常量事件内于尾端安插或移除元素,线性事件内于中间处安插或移除元素。

Deque和vector的差异在于,deque另外还提供常量事件内于序列开头新增或移除元素。在deque开头或尾端安插一个元素,需要O(1)的时间,在中间处安插元素的复杂度与N成线性关系,此处n是安插点距离deque开头语尾端的最短距离。

另一个差异是deque不具备类似vector的capacity()和reserve()之类的memberfunctions,也不提供任何与指向member functions相关之iterator有效性保证。取而代之的是,它保证“将元素安插于deque开头或尾端”不会造成deque中现存的任何元素被复制。对deque而言,类似vector内存重新分配的行为是不会发生的。

一般来说,insert(包括push_front与Push_back)会造成指向deque的所有iterators失效。对deque中调用erase也会造成指向deque的所有iterators失效。至于对着deque的开头或尾端调用erase(包括pop_front与pop_back),则会造成被移除元素的iterator失效。

Deque以动态区段化的数组实现出来。Deque通常内含一个表头,指向一组节点(nodes),每个节点包含固定数量并且连续存储的元素。当deque增长时便增加新的节点。

对于deque和list,内部都有push_back pop_back() push_front() pop_front()

但是对于vector,只有push_back()的 pop_back()

对于set来说:

和List一样,set具有数个重要性质:新元素的安插并不会造成既有元素的iterators失效,从set中删除元素也不会令任何iterators失效----当然被删除元素的iterator除外。因为set是有红黑树来实现的,内部也是以节点的形式存在的。

对于map来说:

和List一样,map具有一个重要性质:新元素的安插不会造成既有元素的iterators的失效。自map中删除元素也不会造成任何iterators失效---除了被删除元素的iterator外。

对于multiset来说:

和List一样,multiset具有数个重要性质:新元素的安插并不会造成既有元素的Iterators失效,从set中删除元素也不会令任何iterators失效—当然被移除元素的iterator除外。

对于multimap来说:

和List一样:multimap具有一个重要性质:新元素的安插不会造成既有元素的iterators的失效。自multimap中删除元素也不会造成任何iterators失效—除了被移除元素的iterator外。

对于priority_queue来说:

它是一个适配器,它实现于某个底部的container之上。缺省的地步型别是vector,但也可以明确指定不同的地步型别。它底部存储元素是用vector来实现的。但是带优先权的队列是标准的数据结构,可以不同方式实现出来。通常priority_queue是以heap来实现,并以算法make_heap、push_heap和pop_heap来维护heap的状态。也就是说优先级队列是有堆来实现的。

对于泛型编程,也就是运用模板,但是在STL中使用了迭代器作为粘合剂,使得容器和算法分离,这样就使得STL更好扩展,模板也是一种多态,属于静态多态,也即是编译期间的多态,在编译期间进行实例化。但是虚拟机制就是运行期多态。是在运行期间才知道在什么时候会被调用。

《泛型编程与STL》这本书讲述了泛型编程在STL中的使用,讲述了什么泛型编程,从使用C++的基本编程来实现自己的需求,然后根据需求再来更新技巧,引出迭代器这个概念,围绕迭代器这个概念来展开,讲述了迭代器的类型,从理论上来分析各种迭代器的属性。进而讲述了算法的重要性,将上述已经介绍过的迭代器引入算法中。引出了容器这个概念,使得迭代器成为容器和算法之间的粘合剂。

在各个容器的实现中定义对外接口,比如各种迭代器和迭代器的类别,这样算法就是根据这些属性来指向,包括为某些容器元素进行偏特化。(偏特化和特化的区别?比如已经定义了一个算法实现的模板,但是为了指针在顶一个模板,这个就是偏特化,但是为了int*这种指针定义一个模板就是特殊。偏特化为某一类重新定义模板(比如为指针这一类),但是特化是为某一个重新定义模板(比如Int*这个类型),在STL中有很多的偏特

对于vector:

成员函数有pop_back() push_back()

对于list  deque:

成员函数有pop_front() push_front() push_back() pop_back()

对于slist:

成员函数有push_front() pop_front()

同时上述这几个容器也有insert()函数

但是上述这几个容器和关联容器的插入操作只有insert()函数

时间: 2024-08-16 01:43:00

泛型编程与STL--各类容器迭代器失效的场景的相关文章

STL容器迭代器失效问题讨论

有的朋友肯定会问, m.erase(it++);就不会产生迭代器失效么? 确实不会! 为什么呢? 这样从it++说起, 为了简便起见, 我们用p++来代替吧. 看程序: #include <iostream> using namespace std; int main() { char szTest[] = "abcdefg"; char *p = szTest; cout << *p++ << endl; return 0; } 大家都知道, 结果

STL容器迭代器失效分析

连续内存序列容器(vector, string, deque) 对于连续内存序列STL容器,例如vector,string,deque,删除当前iterator会使得后面所有的iterator都失效,因为它们使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置,保证元素的连续性.当上述容器的erase方法可以返回下一个有效的iterator,即erase方法的返回的iterator指向紧接在被删除元素之后的元素的有效迭代器,因此,可以根据这个返回值继续访问后面的元素. 连续内存

C++中防止STL中迭代器失效——map/set等关联容器——vector/list/deque等序列容器—如何防止迭代器失效—即erase()的使用

序列性容器::(vector和list和deque) erase迭代器不仅使所有指向被删元素的迭代器失效,而且使被 删元素之后的所有迭代器失效,所以不能使用erase(iter++)的方 式,但是erase的返回值为下一个有效的迭代器,所以   正确方法为:: for( iter = c.begin(); iter != c.end(); ) iter = c.erase(iter); 关联性容器::(map和set比较常用) erase迭代器只是被删元素的迭代器失效,但是返回值为void, 所

STL源码分析--迭代器总结、迭代器失效总结

Vector 1.内部数据结构:连续存储,例如数组. 2.随机访问每个元素,所需要的时间为常量. 3.在末尾增加或删除元素所需时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化. 4.可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存. 5.迭代器失效 插入:vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同).当把超过capacity()-size()个元素插入vector中时,内存会重新分配,所有

C++: STL迭代器及迭代器失效问题

转载至:http://blog.csdn.net/wangshihui512/article/details/9791517 迭代器失效: 典型的迭代器失效. 首先对于vector而言,添加和删除操作可能使容器的部分或者全部迭代器失效.那为什么迭代器会失效呢?vector元素在内存中是顺序存储,试想:如果当前容器中已经存在了10个元素,现在又要添加一个元素到容器中,但是内存中紧跟在这10个元素后面没有一个空闲空间,而vector的元素必须顺序存储一边索引访问,所以我们不能在内存中随便找个地方存储

stl迭代器失效

迭代器(iterator)是一个可以对其执行类似指针的操作(如:解除引用(operator*())和递增(operator++()))的对象,我们可以将它理解成为一个指针.但它又不是我们所谓普通的指针,我们可以称之为广义指针,你可以通过sizeof(vector::iterator)来查看,所占内存并不是4个字节.     首先对于vector而言,添加和删除操作可能使容器的部分或者全部迭代器失效.那为什么迭代器会失效呢?vector元素在内存中是顺序存储,试想:如果当前容器中已经存在了10个元

STL erase() 迭代器失效

STL中的容器按存储方式分为两类:序列容器(如:vector .deque):关联容器(如:list.set.map) 两种容器在使用erase方法来删除元素时或产生迭代器失效的问题 对于关联容器 1 std::list<int> List; 2 std::list<int>::iterator iter = List.begin(); 3 for(;iter!=List.end();) 4 { 5 if(needDelete(*iter)) 6 { 7 iter= List.er

stl的erase()陷阱--迭代器失效总结

1.list,set,map容器 在使用 list.set 或 map遍历删除某些元素时可以这样使用: 1.1 正确写法1 1 std::list< int> List; 2 std::list< int>::iterator itList; 3 for( itList = List.begin(); itList != List.end(); ) 4 { 5 if( WillDelete( *itList) ) 6 { 7 itList = List.erase( itList)

STL迭代器失效总结

转自: http://blog.csdn.net/hackbuteer1/article/details/7734382             http://m.blog.csdn.net/blog/xhu_eternalcc/38355619 迭代器(iterator)是一个可以对其执行类似指针的操作(如:解除引用(operator*())和递增(operator++()))的对象,我们可以将它理 解成为一个指针.但它又不是我们所谓普通的指针,我们可以称之为广义指针,你可以通过sizeof(