标准中的§23.1.2.8声明对set/map的插入/删除操作不会使对这些对象的任何迭代器无效(指向已删除元素的迭代器除外).
现在,考虑以下情况:您希望实现具有唯一编号节点的图形,其中每个节点具有固定数量(假设4个)邻居.利用上述规则,你可以这样做:
class Node {
private:
// iterators to neighboring nodes
std::map<int, Node>::iterator neighbors[4];
friend class Graph;
};
class Graph {
private:
std::map<int, Node> nodes;
};
Run Code Online (Sandbox Code Playgroud)
(编辑:由于Node第4行的不完整性(参见回复/评论),并非字面意思,但无论如何都沿着这些方向)
这很好,因为这样您就可以插入和删除节点而不会使结构的一致性失效(假设您跟踪删除并从每个节点的数组中删除已删除的迭代器).
但是,假设您还希望能够存储"无效"或"不存在"的邻居值.不用担心,我们可以使用nodes.end()...或者我们可以吗?是否存在某种保证,nodes.end()在nodes.end()经过多次插入/删除后,上午8点将与下午10点相同?也就是说,我可以安全地==将作为参数接收的迭代器nodes.end()与Graph的某些方法进行比较吗?
如果没有,这会有效吗?
class Graph {
private:
std::map<int, Node> nodes;
std::map<int, Node>::iterator _INVALID;
public:
Graph() { _INVALID = nodes.end(); }
};
Run Code Online (Sandbox Code Playgroud)
也就是说,我可以nodes.end()在构造时存储变量,然后每当我想将邻居设置为无效状态时使用此变量,或者将它与方法中的参数进行比较吗?或者有可能在某个地方,指向现有对象的有效迭代器将比较等于_INVALID?
如果这也不行,有什么可怎么办留有余地无效邻居价值?
你写(强调我):
标准中的§23.1.2.8声明对set/map的插入/删除操作不会使对这些对象的任何迭代器无效(指向已删除元素的迭代器除外).
实际上,23.1.2/8的文本有点不同(再次,我强调):
插入成员不应影响迭代器和对容器的引用的有效性,并且擦除成员应仅使迭代器和对已擦除元素的引用无效.
我读这个:如果你有一个地图,并以某种方式获得一个迭代器到这个地图(再次:它没有说明地图中的对象),这个迭代器将保持有效,尽管插入和删除元素.假设std::map<K,V>::end()获得"迭代器到地图",它不应该通过插入/删除无效.
当然,这留下了一个问题,即"未通过无效"意味着它将始终具有相同的值.我个人的假设是没有具体说明.但是,为了使"无效"短语有意义,std::map<K,V>::end()即使面对插入/删除,同一地图的所有结果也必须始终相等:
my_map_t::iterator old_end = my_map.end();
// wildly change my_map
assert( old_end == my_map.end() );
Run Code Online (Sandbox Code Playgroud)
我的解释是,如果old_end在对地图的更改(作为标准的承诺)中保持"有效",那么该断言应该通过.
免责声明:我不是母语人士,并且非常难以消化神圣PDF的可怕法律.事实上,总的来说,我就像瘟疫一样避免它.
哦,我的第一个想法也是:这个问题很有趣,来自学术POV,但为什么他不只是存储键而不是迭代器?
23.1/7 说 end() 返回一个迭代器
是容器的期末值。
首先,它确认end()返回的是迭代器。其次,它表示迭代器不指向特定元素。由于删除只能使指向某处(指向被删除的元素)的迭代器无效,因此删除不能使end().