仅为容器提供const迭代器有意义吗?

Does it make sense to provide only const iterators for a container?

本文关键字:迭代器 有意义 const      更新时间:2023-10-16

我有一个类似于下一个的容器:

class MySpecialContainer
{
    std::vector<std::tuple<InternalType, Type1, Type2>> _vec;
};

,其中Type1Type2可以在容器外使用,InternalType只能在容器内使用。为了从外部遍历元素,我使用了一个类似于下一个的成员函数:

void MySpecialContainer::iterate(std::function<void(const Type1&, const Type2&)> fun)
{
    for(auto& it : _vec)
    {
        fun(std::get<1>(it), std::get<2>(it));
    }
}

正如您所看到的,这种方法有几个限制,比如不能在子范围上迭代,或者不能使用非突变的std::algorithms

考虑到MySpecialContainer元素从逻辑考虑是不可变的,它有意义只提供const_iterator为它吗?

如果第一个问题的答案是肯定的,那么……是否更好?

  1. _vec分离到2个容器中,一个用于InternalType,一个用于std::pair<Type1, Type2>,保持它们同步,仅返回const_iterator作为第二个向量

  2. 保持vector现在的样子,并创建一个只暴露const Type1const Type2的自定义迭代器

只暴露const迭代器就可以了。这在标准中甚至有优先级,因为std::set有效地做到了这一点。从技术上讲,iteratorconst_iterator可以是不同的类型,但不允许通过任何一种类型的迭代器修改元素,因为这可能会破坏set的不变量。

一种选择是公开只允许访问元素的特定字段的迭代器,例如:

#include <vector>
#include <tuple>
#include <boost/iterator/transform_iterator.hpp>
struct Type1 {};
struct Type2 {};
struct InternalType {};
class MySpecialContainer
{
    typedef std::vector<std::tuple<InternalType, Type1, Type2>> Vec;
    Vec _vec;
    struct Extractor
    {
        std::tuple<Type1&, Type2&> operator()(Vec::value_type& t) const {
            return std::tie(std::get<1>(t), std::get<2>(t));
        }
        std::tuple<Type1 const&, Type2 const&> operator()(Vec::value_type const& t) const {
            return std::tie(std::get<1>(t), std::get<2>(t));
        }
    };
public:
    typedef boost::transform_iterator<Extractor, Vec::iterator> iterator;
    typedef boost::transform_iterator<Extractor, Vec::const_iterator> const_iterator;
    iterator begin() { return iterator{_vec.begin()}; }
    iterator end() { return iterator{_vec.end()}; }
    const_iterator begin() const { return const_iterator{_vec.begin()}; }
    const_iterator end() const { return const_iterator{_vec.end()}; }
};
int main() {
    MySpecialContainer c;
    for(auto x : c) {
    }
}

请注意,通过非常量迭代器,您仍然可以更新暴露的值,因为转换迭代器返回一个引用元组。