在STL map/set中end()是否必须是常量?

sus*_*att 34 c++ iterator stl

标准中的§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

如果这也不行,有什么怎么办留有余地无效邻居价值?

sbi*_*sbi 5

你写(强调我):

标准中的§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,但为什么他不只是存储键而不是迭代器?


P S*_*ved 5

23.1/7 说 end() 返回一个迭代器

是容器的期末值。

首先,它确认end()返回的是迭代器。其次,它表示迭代器不指向特定元素。由于删除只能使指向某处(指向被删除的元素)的迭代器无效,因此删除不能使end().


Dew*_*wfy 1

假设(1)用红黑树实现的映射(2)“在无数次插入/删除之后”使用相同的实例 - 回答“是”。

相对实现我可以看出我所知道的所有 stl 的化身都使用树算法。