对于 C++ Random Access Iterator(向量迭代器),迭代器之间的差异是如何计算的?

Posted

技术标签:

【中文标题】对于 C++ Random Access Iterator(向量迭代器),迭代器之间的差异是如何计算的?【英文标题】:For C++ Random Access Iterator (vector iterator), how is the difference between iterators calculated? 【发布时间】:2020-01-06 06:28:32 【问题描述】:

我有以下代码来随机化随机访问迭代器中的元素 (vector<int>::iterator) -

#include <vector>
#include <list>
#include <iterator>
#include <algorithm>
#include <stdlib.h>
#include <iostream>
using namespace std;

template<class RandomAccesIterator>
void randomize(RandomAccesIterator iterBegin, RandomAccesIterator iterEnd)

    while (iterBegin != iterEnd)
    
        int rand1 = rand();
        auto iterdiff = iterEnd - iterBegin;
        auto secondarg = iterBegin + rand1 % (iterdiff);
        iter_swap(iterBegin, secondarg);
        ++iterBegin;
    

以下是main()函数:

int main()

    //container used as to apply algorithm to.
    list<int> List = 34,77,16,2,35,76,18,2,56;

    //randomize example.
    cout << "calling randomize on sorted vector: " << endl;
    List.sort();
    vector<int> temp(List.begin(), List.end());
    cout << "before randomize: " << endl;
    for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++)
    
        cout << *it << " ";
    
    cout << endl;

    randomize(temp.begin(),temp.end());
    cout << "after randomize: " << endl;
    for (vector<int>::iterator it = temp.begin(); it != temp.end(); it++)
    
        cout << *it << " ";
    
    cout << endl<<endl;
    return 0;

在randomize模板函数中,迭代器之间的差值是如何计算的(iterEnd - iterBegin)?

我在即时窗口中尝试了几件事,它看起来像 iterEnd - iterBegin 是这样计算的(向量中有 9 个元素,下面的计算给出 9)。我尝试在vector&lt;int&gt; 中使用各种数量的元素,并且每次的答案都是正确的。计算是我们第一次在while循环中遇到iterEnd - iterBegin(即对于向量中的9个元素):

在即时窗口中 -

1.

iterEnd
-33686019
    [ptr]: 0x0080f9dc -33686019
    [Raw View]: ...

2.

iterBegin
2
    [ptr]: 0x0080f9b8 2
    [Raw View]: ...

3.

0x0080f9dc-0x0080f9b8 //iterEnd - iterBegin gives 36.
36

4.

36/4 //Dividing 36 by 4, since an integer is 4 bytes (we are iterating over a vector of integers).
9

我还尝试了vector&lt;int&gt; 中的 8 个元素,相同类型的计算在上面的第 4 步中得到了 8 个元素。

我有几个问题:

    我为获取向量中的元素数量而执行的步骤是否正确(上述步骤 1. 到 4.)? 在上面的第 4 步中,我将 36(十进制)除以 4 个字节。这如何给我正确的结果?如果我将 36 个字节除以 4 个字节,那么这将给我 9 个元素。为什么将 decimal 36 除以 4 个字节给出正确答案?

请参阅:我正在使用以下编译器:Microsoft Visual Studio Enterprise 2019(版本 16.2.1)。操作系统平台是 64 位、基于 x64 的处理器。我正在调试 x86 环境中构建。 Windows 版本是 Windows 10 Pro

【问题讨论】:

这是您正在使用的标准库的实现细节。你可能不应该玩弄它。如果您仍然想知道库在做什么,那么您应该将您正在使用的编译器/平台添加到问题中,因为每个编译器/平台都会有所不同。 如果该随机访问迭代器是一个指针 - 这当然是一种选择 - 它是一个直接减法(减去两个指向 T 的指针得到一个 ptrdiff_t 这是一个有符号整数值,代表差异/他们之间的距离)。如果那个迭代器是别的东西,那么这个“别的东西”将被设计成计算它们之间的差异是有意义的。 您可以查看MS STL源代码以了解std::vector::iterator是如何实现的。它是一个 class,它只是 wraps a pointer 到向量的值类型。 RandomAccessIterator (vector::iterator) 的迭代器是连续的吗?只有这样,划分 (iterEnd - iterBegin)/sizeof(int*) 才有意义,并得到正确的结果。 "RandomAccessIterator 的迭代器是连续的吗?"不一定。 C++17 增加了类别ContiguousIterator which vector::iterator models 【参考方案1】:

你的步骤是正确的,但仅仅是因为:

int你的系统上恰好有 4 个字节长 std::vector&lt;int&gt;::iterator 碰巧在你的系统上简单地包装了一个原始指针 (int*)

您可以使用sizeof(int) 来评估编译代码的任何系统上的正确字节数,而不是硬编码值 4。

std::size_t numElements = (0x0080f9dc - 0x0080f9b8) / sizeof(int);  // Better

至于您的第二个问题,您正在计算的36 不是无单位的十进制值。原始指针的原始整数值(请记住:std::vector&lt;int&gt;::iterator 简单地包装了一个 int*,因此它具有相同的大小)使用字节作为它们的隐式单位,因此您 实际上是将字节除以你的步骤。

最后,我建议避免使用这种指针算法 (rationale)。该标准已经提供了一个函数来精确计算这一点,std::distance,它可以在所有标准迭代器和你编译代码的任何系统上正常工作。

std::size_t numElements = std::distance(iterBegin, iterEnd);  // Best

【讨论】:

如果iterEnditerBeginint*类型,那么它们之间的区别不是字节而是元素,所以sizeof(int)的划分是不必要的。 std::vector&lt;int&gt;::iterator 不是 OP 系统上的原始指针。请参阅@Daniel 在问题 cmets 中链接的 Microsoft 标准库实现 the link。 似乎实现只是简单地包装了所有操作,所以我将放宽我的措辞。 看起来 iterEnd 和 iterBegin 之间的区别确实以字节为单位。当我将vector 更改为vector 时,我在执行iterEnd - iterBegin 时得到以下结果:0x00bfe151-0x00bfe148 =9。而 9/sizeof(char) 给出 9 个元素。 vector 中有 9 个元素。在上面的 OP 中,我们有一个 vector 代替,它包含 9 个元素,以下是执行 iterEnd - iterBegin 的结果:0x0080f9dc-0x0080f9b8 = 36 字节。并且,36/sizeof(int) 给出 9(vector 中的元素数)。我是否正确 iterEnd - iterBegin 给出了字节的差异?

以上是关于对于 C++ Random Access Iterator(向量迭代器),迭代器之间的差异是如何计算的?的主要内容,如果未能解决你的问题,请参考以下文章

Lesson 031 —— random 模块

C++ 使用 iter_swap 改变向量的顺序

iter的一种用法

c++ boost::iterator_range<iter> string_view 错误

C++从vector中删除指定元素

256 terabytes random-access memory