自定义迭代器中distance_type的目的 - std::d istance(first, last) 将返回错误的

The purpose of the distance_type in a custom iterator - std::distance(first, last) will return a wrong result, if first and last are too far way

本文关键字:first last 错误 返回 istance type distance 迭代器 自定义 std      更新时间:2023-10-16

我想为自定义类实现一个迭代器

template</*...*/>
class foo
{
public:
    using value_type = /* depends on template parameters */;
    using size_type = /* depends on template parameters */;
    class iterator
        : public std::iterator<std::random_access_iterator_tag, value_type, /* some suitable difference_type compatible to size_type */>
    {
    public:
        iterator(foo& bar, size_type i)
            : m_bar(bar), m_i(i),
              m_dereferenceable(i != bar.size())
        { }
    private:
        foo& m_bar;
        size_type m_i;
        bool m_dereferenceable;
    };
    size_type size() const { /* ... */ }
    value_type operator[](size_type) { /* ... */ }
};

并想知道我应该如何实施operator+=(difference_type).我已经将difference_type定义为对我来说完全有意义的std::make_signed_t<size_type>原因。

关键的一点是:我认为将m_i定义为类型 size_type 是合理的,确保其值被固定为[0, m_bar.size()]并使用标志m_dereferenceable来处理具有m_i == 0iterator递减的情况。

这有点复杂,如果我将m_i类型更改为签名类型difference_type,一切都会更容易。但是,如果m_bar的大小正在利用整个size_type范围,这将阻止我迭代整个范围。

现在,我意识到(例如(std::distance 的返回类型是 difference_type 。一方面,这是合理的,因为我们可能会有负距离。另一方面,如果m_bar的大小正在利用整个size_type范围,std::distance可能会返回错误的结果。

所以,问题是:请记住(例如(std::distance可能会返回错误的结果,如果我将m_i定义为类型 size_type ,我是否应该简单地使用 difference_type 代替(并从更容易的实现中受益(?


编辑:让我强调以下几点:假设我们有一个vector x vector = std::vector</* ... */>并执行x.resize(std::numeric_limits<vector::size_type>::max())

由于d = std::distance(x.begin(), x.end())的类型是vector::difference_type的,s = x.size()的类型是vector::size_type的,我很好奇d是否会等于s

这个问题不是关于vector,而是一个关于size_typedifference_type的整个概念以及它们对迭代器的目的的问题。

请忽略任何技术问题(内存处理等(,并将size_type视为"复杂的东西"(即对"大小"表示的理解的抽象(。

显然,d必须是有符号类型,因为我们可能有负距离。当然,我可以想到一些技术问题,这些问题阻止了标准保证difference_type对象必须能够存储size_type对象。但是由于STL是关于泛型编程的,我很惊讶。

你应该知道,size_typedifference_type只是容器分配器或迭代器自己的typedef的typedef。它们与向量本身完全无关。

除此之外,我认为你从整体上想得太多了。 size_typedifference_type是两种概念上不同的类型:

difference_type: 有符号整数类型,表示序列中任意两个元素的地址之差

size_type: 表示序列长度的无符号整数类型

每当使用返回其中任一类型的函数时,它们都会返回与其定义一致的值。有了std::distance真的找到了容器的尺寸吗?不,您正在发现两个迭代器之间的区别。使用std::size,您没有发现迭代器之间的任何差异,您正在检索一个应该具有逻辑意义的值,一个表示容器大小的unsigned整数类型。这只是比返回signed类型的更好表示形式,如您所知,容器的长度将始终为正数。

因此,您可以侥幸使用difference_type,毕竟您将始终能够安全地使用std::distance计算容器的大小。

但是你应该吗?

size_type只是无符号difference_type表示形式。仅此而已,只是保证能够保存代表容器大小的值。

判决

你可以少打字,从代码中省略size_type,但我强烈建议不要这样做。这是标准的一部分,在逻辑上是有意义的。当你计算两个对象的差值时,结果必须能够处理负数,但大小永远不会有这个问题,那么为什么要将其定义为signed