分享
 
 
 

Item 1:小心地选择你的容器

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Item 1:小心地选择你的容器

scott meyers 著

刘未鹏 译

你知道C++提供了多种容器让你支配,但是你了解它们到底有多少种吗?为了使你能对自己能够做出的选择有一个清晰的概观,这儿提供了一个快速的回顾:

* standard STL sequence containers(标准的STL序列式容器)有vector,string,deque,list。

* standard STL associative containers(标准的STL关联式容器)有set,multiset,map,multimap。

* nonstandard sequence containers(非标准的序列式容器)有slist,rope。slist是单向链表而rope从本质上是一个heavy-duty string。在条款50你可以看到关于这些非标准的(但一般是有用的)容器的一个简要的概观。

* nonstandard associative containers(非标准的关联式容器)有hash_set,hash_multiset,hash_map, hash_multimap.我考察了这些被广泛使用的“hash-table-based”容器(条款25)。

* 以vector<char>来替代string。条款13描述了在什么样的情况下这样的替换可能是有意义的。

* 以vector来替代标准关联式容器。如条款23所表明的,有些时候vector在空间和时间上都要胜过关联式容器。

* standard non-STL containers(一些标准的非STL容器)有array,bitset,valarray,stack ,queue,priority-queue.因为这些是non-STL容器。在这本书里我对它们讲得很少,尽管条款16提到了一种arrays比STL容器好的情况。条款18解释了为什么bitset比vector<bool>要好。还有,值得记住的是array可以与STL算法合作无间,因为指针(译注:指原生指针)可被用来作为array的迭代器(译注:事实上,迭代器正是一种类似指针行为的concept)。

可选择的如此之多。在可以考虑的范围内仍有大量符合的结果,你得在它们之中选择。不幸的是,绝大多数有关STL的讨论在容器方面的笔墨相当贫乏,忽略了关于”如何选择最合适的容器”的问题的讨论。甚至连C++ Standard都介入了,并提供了以下在vector,deque,和list之间选择的原则:

vector,list,deque提供了不同的复杂性协定,应该依照使用。vector是缺省使用的序列式容器,list应该在频繁需要在序列式容器中部插值或删值的情况下使用(译注:这时如果使用vector会因为可能大量搬动元素或甚至重分配空间而效率低下)。而当绝大多数插入和删除操作都是在容器头部和尾部时就该用deque(译注:deque的头尾都可扩展的特点保证了这一点)。

如果你的主要考虑是算法复杂度,我想这是合理的建议,但是有太多其他的东西得考虑。

我们马上就来考察一些重要的容器相关的使算法完备的问题,但首先我需要向你介绍一种将STL容器分类的方法(这并没有象它应该的那样经常被讨论)。那就是“内存连续式”(contiguous-memory)容器和”基于节点的”(node-based)容器之间的区别。

“内存连续式”容器(也被称为array-based容器)把它的对象保存在动态分配的大块连续内存(chunk)中。每个chunk都含有一个以上的元素。如果插入(insert)一个新的元素或擦除(erase)现有的元素,则其它在同一个chunk中的元素都需要向前或向后移动,以便给新元素挪出空间(insert的时候)或是去占据被擦除元素原来所占的空间(erase的时候)。这种移动对性能(见条款5和14)和异常安全(不久我们就会看到)都会产生影响。标准“内存连续式”容器有vector,string,deque。非标准的rope也是“内存连续式”的。

node-based容器在一个动态分配的chunk(一块连续的内存)中有且仅有一个元素。insert或是erase只会影响指向节点的指针,而不会影响节点本身的内容,所以当insert或是erase时元素的值并不需要被移动。链表形式的容器如list,slist是node-based容器,所有的标准关联式容器也一样(典型的,它们在内部以平衡树的形式实现(译注:如红黑树))。非标准的哈希(hashed)容器在内部以可以有多种不同的node-based实现,正如你将在条款25所看到的。

我们将会讨论一些与容器的选择息息相关的问题。在讨论中,我忽略了non-STL-like的容器(arrays,bitsets.etc.),因为这毕竟是一本关于STL的书。

* 你需要能在容器的任意位置插入新元素的能力吗?如果是的,你需要一个序列式容器,关联式容器不行。

* 你关心元素在容器中是如何排序的吗?如果不,哈希容器会是个有价值的选择。其它时候你应该避免哈希容器。

* 你的容器一定要是C++标准的一部分吗?如果是,请排除掉哈希式容器,slist和rope。

* 你需要哪一类迭代器?如果如果它们必须是随机存取迭代器,从技术上讲你就只能选择vector,deque,和string,但是你也可能会想要考虑rope(见条款50)。如果你需要双向迭代器,避免使用slist,和”以通常的方式实现”的哈希容器。

* 你不想现有元素在插入和擦除时被移动吗?如果是,请与“内存连续式”容器保持距离(条款5)。

* 容器中的数据布局需要与C兼容吗?如果是,你只能选择vector(条款16)

* 查找速度是一个重要的考虑因素吗?如果是,你得看看哈希容器(条款25),sorted vector(经过排序的vector)(条款23),和标准关联式容器

* 你介意底层容器采用引用记数(reference-counting)吗?如果介意的话,你得避开string,因为许多string的实现都采用了引用记数技术(条款13)。你也要避免使用rope,因为明确定义的rope是在引用记数的基础上实现的(条款50)。当然,你总要以某种方法来表现你的string吧,所以你可以考虑使用vector<char>。

* 在插入或擦除元素时你需要”原子事务处理”的语义吗?也就是说,你需要可靠的撤消或回退操作(roll back)吗?如果是,你可以使用node-based容器。更进一步,你需要对多个元素的插入移除也具有”原子事务处理”语义的容器吗(条款5)?如果是,你可以选择list,因为它是唯一提供多元素原子事务处理语义的容器。”原子事务处理”语义对异常安全(exception-safty)的代码特别重要(原子事务处理语义也能在“内存连续”式容器里实现,但是会有性能开销,代码也会变得不易懂,Sutter的《Exceptional C++》条款17提供了这方面更多的信息)(译注:当异常产生时必须保证进行到一半的操作能够回退,以保持数据的一致性)。

* 你想使迭代器、指针、引用的失效降到最低吗?如果是,你得使用node-based容器,因为在这类容器上插入和擦除从不会使迭代器、指针、引用失效(当然,除非它们刚好指向你要擦除(erase)的元素)。而在“内存连续式”容器上插入或擦除则可能使迭代器、指针、引用失效。

* 使用一个只要在尾部插入或擦除就不会使迭代器、指针、引用失效的,并具有随机存取迭代器的序列式容器会有帮助吗?这是一种非常特殊的情况,但如果这恰恰是你所遭遇的情况,deque就是你梦寐以求的容器(有趣的是,在deque的尾部插入新元素也可能使迭代器失效(译注:事实上,当插入元素导致deque的中控器重新配置时这种情况就会出现),deque是唯一的可以在迭代器失效的同时指针和引用却不失效的标准STL容器)。

以上这些考虑还远远不是问题的尽头。比如,它们并没有将不同类型容器间的多样化的内存配置策略考虑进去(条款10和条款14讨论了这些策略的一些方面。尽管如此,以上所列举的已经足够让你相信:除非你对元素的排序、与标准的一致性、迭代器的能力(译注:指的是迭代器是input,output,forward,bidirectional还是random)、与C的内存布局的兼容性、查找速度、引用记数带来的行为反常、实现了原子事务所带来的安逸、在怎么样的情况下迭代器会失效,统统都没有兴趣,否则你会有更多的要去考虑,而不是简单的只考虑容器的操作的算法复杂度。当然,算法复杂度是重要的,然而这它只是整个故事的一小部分。

在容器方面,STL给了你许多选择。如果你跳出STL的圈子,甚至还会有更多的选择。在选择一个容器之前,一定要考虑你的选择的方方面面。一个“缺省的容器”?我不这样认为。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有