公开私有范围的Boost.BiMap迭代器的公共视图

时间:2012-01-28 17:47:02

标签: c++ boost iterator bimap

我在一个类中有一个私有范围的Boost.BiMap,我想导出这个地图的一部分的公共视图。我对以下代码有两个问题:

class Object {

    typedef bimap<
        unordered_set_of<Point>,
        unordered_multiset_of<Value>
    > PointMap;

    PointMap point_map;

public:
    ??? GetPoints(Value v) {
    ...
}

第一个问题是我的迭代方法是否与Point相关联的Value是正确的。下面是我用来迭代点的代码。我的问题是,如果我正在迭代,因为我发现我必须包含it->first == value条件,并且不确定这是否是必需的,因为我可能不了解更好的界面。

PointMap::right_const_iterator it;
it = point_map.right.find(value);
while (it != point_map.right.end() && it->first == val) {
    /* do stuff */
}

第二个问题是提供GetPoints(上面的???返回类型)的公共视图的最佳方法是什么,而不暴露bimap迭代器,因为看起来调用者必须知道{{1 }}。任何有效的结构,例如引用列表或集合都可以工作,但是我对如何创建集合感到有点迷失。

谢谢!

1 个答案:

答案 0 :(得分:0)

第一个问题:

由于您在bimap类型的右侧使用unordered_multiset_of集合类型,这意味着它将具有与std::unordered_multimap兼容的接口。 std::unordered_multimap具有成员函数equal_range(const Key& key),它返回std::pair个迭代器,一个指向具有所需键的第一个元素,另一个指向超出元素范围末尾的一个元素。具有相同的密钥。使用它可以使用匹配键迭代范围,而无需将键与迭代条件中的值进行比较。

请参阅http://www.boost.org/doc/libs/1_41_0/libs/bimap/doc/html/boost_bimap/the_tutorial/controlling_collection_types.htmlhttp://en.cppreference.com/w/cpp/container/unordered_multimap/equal_range以获取参考资料。

第二个问题:

构造一个列表或其他实际容器的指针或对具有匹配值的元素的引用并返回它是低效的,因为它总是需要O(n)空间,而只是让用户迭代原始范围bimap只需要返回两个迭代器,它只需要O(1)内存。

您可以编写直接返回迭代器的成员函数,例如

typedef PointMap::right_const_iterator match_iterator;

std::pair<match_iterator, match_iterator> GetPoints(Value v) {
    return point_map.right.equal_range(v);
}

或者您可以编写一个代理类,通过让begin()和end()成员函数返回这两个迭代器来呈现类似容器的接口,并让您的GetPoints()成员函数返回该类型的对象:

class MatchList {

    typedef PointMap::right_const_iterator iterator;

    std::pair<iterator, iterator> m_iters;

public:

    MatchList(std::pair<iterator, iterator> const& p) : m_iters(p) {}

    MatchList(MatchList const&) = delete;

    MatchList(MatchList&&) = delete;

    MatchList& operator=(MatchList const&) = delete;

    iterator begin() { return m_iters.first; }

    iterator end() { return m_iters.second; }
};

最好让它不可复制,不可移动和不可分割(就像我上面通过删除相关的成员函数所做的那样),因为用户可能会另外保留代理类的副本并在迭代器中尝试访问它可能会失效。

第一种方式意味着编写更少的代码,第二种方式意味着向用户提供更常见的界面(如果您需要稍后修改实现,则允许在代理类中隐藏更多内容)。