我需要一种方法来快速访问容器中的数据。
我记得那个数据位置的迭代器。在此之后,容器可能会被修改(添加和删除元素),但如果我使用的容器类型不会使我的迭代器无效(如std::map
或std::list
),我就没事了。
也我的数据可能不在容器(尚未),所以我设置了一个迭代器为container.end()
来反映这一点。
哪个标准容器保证end()
在添加和删除元素时不会改变?因此,我仍然可以将我的迭代器与container.end()
返回的值进行比较,而不会得到假阴性
23.2.4/9 of Associative Containers:
插入和放置构件不影响构件的有效性对容器的迭代器和引用,以及erase成员只使迭代器和对已删除元素的引用无效
现在,标准中有一些地方谈到不使"迭代器和对容器元素的引用"失效,因此不包括end()
。我不相信这是其中之一——我很确定end()
迭代器是一个"容器迭代器"。
23.3.5.4/1说std::list
的insert
"不影响迭代器和引用的有效性",而23.3.5.4/3说erase
"只使被擦除元素的迭代器和引用无效"。同样,end()
迭代器也是迭代器,因此不排除其有效性。
需要注意的一点是,对于任何容器,swap
都可以使end()迭代器无效(我认为这是因为有两种"自然"行为,结束迭代器要么指向相同容器的末端,要么指向被交换的容器的末端,但标准不想规定哪一种或排除其他可能性)。但是你没有交换,只是添加和删除元素。
根据我的经验,std::vector
和std::dequeue
中的迭代器在擦除或添加时调整大小时会中断(这也适用于std::string
的存储)。std::list
和std::map
不分配内存块:它们通常分配单个节点(并且大多数std::unordered_map
实现将bucket作为项目的链表(例如std::list
))。
如果你需要一个幸存的end()
迭代器,选择一个std::list
(我这样做是为了我的信号/插槽实现,为了他们的令牌)或者用std::vector
/std::dequeue
做你自己的个人记账。
编辑
:因此,std::list
是一种让迭代器始终有效的好方法,前提是列表本身永远不会死亡(它们不会死亡)。从另一个答案,如果你需要标准的清晰度:
23.3.5.4/1说for std::list insert"不影响迭代器和引用的有效性",而23.3.5.4/3说erase"只使被删除元素的迭代器和引用无效"。同样,end()迭代器也是迭代器,因此不排除它们的有效性。——另一个答案
使用vector
代替迭代器并存储索引值。他们会在任何重组中幸存下来。迭代器主要用于成对使用,用于指定一个范围;正如您所看到的那样,保留单个迭代器会变得很混乱。