【问题标题】:Understanding Iterators in the STL了解 STL 中的迭代器
【发布时间】:2011-08-02 04:39:30
【问题描述】:

C++ STL 中的迭代器到底是什么?

在我的例子中,我使用的是list,我不明白为什么你必须创建一个迭代器std::list <int>::const_iterator iElementLocator; 来通过 derefrence 运算符显示列表的内容:
cout << *iElementLocator; after将其分配给list.begin()

请解释一下迭代器到底是什么以及为什么我必须取消引用或使用它。

【问题讨论】:

    标签: c++ stl iterator


    【解决方案1】:

    STL 中有三个构建块:

    • 容器
    • 算法
    • 迭代器

    在概念级别,容器保存数据。这本身并不是很有用,因为您想对数据一些事情;你想操作它,操纵它,查询它,玩弄它。算法正是这样做的。但是算法不保存数据,它们没有数据——它们需要一个容器来完成这项任务。给算法一个容器,你就有了一个动作。

    从技术角度来看,唯一需要解决的问题是算法如何遍历容器。从技术上讲,容器可以是链表,也可以是数组、二叉树或任何其他可以保存数据的数据结构。但是遍历数组与遍历二叉树的方式不同。尽管从概念上讲,算法想要的只是一次从容器中“获取”一个元素,然后处理该元素,但从容器中获取下一个元素的操作在技术上是非常容器化的——具体的。

    您似乎需要为每个容器编写相同的算法,以便每个版本的算法都有用于遍历容器的正确代码。但是有一个更好的解决方案:让容器返回一个可以遍历容器的对象。该对象将有一个接口算法知道。当算法要求对象“获取下一个元素”时,对象会遵守。因为对象直接来自容器,所以它知道如何访问容器的数据。而且因为对象有一个算法知道的接口,我们不需要为每个容器复制一个算法。

    这是迭代器。

    这里的迭代器将算法粘合到容器中,而不会将两者耦合。迭代器耦合到容器,算法耦合到迭代器的接口。这里的神奇之处在于模板编程。考虑标准的copy() 算法:

    template<class In, class Out>
    Out copy(In first, In last, Out res)
    {
        while( first != last ) {
            *res = *first;
            ++first;
            ++res;
        }
        return res;
    }
    

    copy() 算法将两个以In 类型模板化的迭代器和一个Out 类型的迭代器作为参数。它将从位置first 开始并在位置last 之前结束的元素复制到res。算法知道要获得下一个元素,它需要说出++first++res。它知道要读取一个元素需要说x = *first,而要写入一个元素需要说*res = x。这是接口算法假设和迭代器承诺的一部分。如果错误地迭代器不符合接口,那么当类型未定义函数时,编译器将发出错误调用类型为 InOut 的函数。

    【讨论】:

    • 可能是从高层次上描述 STL 的最佳方式之一,谢谢!
    【解决方案2】:

    我很懒惰。所以我不会描述什么是迭代器以及它们是如何使用的,尤其是当网上已经有很多文章可供您自己阅读时。

    这里有几个我可以引用的开始,提供完整文章的链接:

    MSDN 说,

    迭代器是 指针,从它们的抽象 要求以允许的方式 C ++程序可以使用不同的 统一的数据结构。 迭代器充当中介 在容器和泛型之间 算法。而不是在 具体的数据类型,算法是 定义为在一个范围内操作 由迭代器类型指定。任何 满足的数据结构 然后迭代器的要求可以 由算法操作。那里 是五种类型或类别 迭代器 [...]

    顺便说一句,似乎 MSDN 已经从 C++ 标准本身中提取了粗体文本,特别是从第 §24.1/1 节中说的

    迭代器是 允许 C++ 程序的指针 使用不同的数据结构 (容器)以统一的方式。 能够构建模板 正确工作的算法和 有效地处理不同类型的数据 结构,图书馆正式不 只是接口,还有 语义和复杂性假设 的迭代器。我支持的所有迭代器 表达式 *i,产生一个 某个类、枚举的值,或 内置类型 T,称为值类型 的迭代器。 i 的所有迭代器 表达式 (*i).m 是 定义明确,支持表达式 i->m 具有相同的语义 (*我是。对于每个迭代器类型 X 为 定义了哪个等式,有一个 对应的有符号整数类型 称为差异类型 迭代器。

    cplusplus 说,

    在 C++ 中,迭代器是任何对象 那,指向 a 中的某个元素 元素范围(例如数组或 一个容器),有能力 遍历那个元素 使用一组运算符的范围(在 至少,增量 (++) 和 取消引用 (*) 运算符)。

    迭代器最明显的形式是 指针 [...]

    您还可以阅读以下内容:

    请耐心阅读所有这些内容。希望您对 C++ 中的迭代器有所了解。学习 C++ 需要耐心和时间。

    【讨论】:

      【解决方案3】:

      迭代器与容器本身不同。迭代器引用容器中的单个项目,并提供访问其他项目的方法。

      考虑设计您自己的不带迭代器的容器。它可以有一个size 函数来获取它包含的项目数,并且可以重载[] 运算符以允许您通过其位置获取或设置一个项目。

      但是这种“随机访问”并不容易在某些容器上有效地实现。如果您获得第 100 万个项目:c[1000000],并且容器内部使用链表,则它必须扫描一百万个项目才能找到您想要的。

      您可能会决定允许集合记住“当前”项。它可以具有 startmorenext 之类的功能,以允许您循环浏览内容:

      c.start();
      while (c.more()) 
      {
          item_t item = c.next();
      
          // use the item somehow
      }
      

      但这会将“迭代状态”放入容器中。这是一个严重的限制。如果您想将容器中的每个项目与其他所有项目进行比较怎么办?这需要两个嵌套循环,都遍历所有项目。如果容器本身存储了迭代的位置,你就没有办法嵌套两个这样的迭代——内循环会破坏外循环的工作。

      所以迭代器是迭代状态的独立副本。您可以开始迭代:

      container_t::iterator i = c.begin();
      

      那个迭代器,i,是一个单独的对象,代表容器中的一个位置。您可以获取存储在该位置的任何内容:

      item_t item = *i;
      

      您可以移至下一项:

      i++;
      

      使用一些迭代器,您可以向前跳过几个项目:

      i += 1000;
      

      或者在相对于迭代器标识的位置的某个位置获取项目:

      item_t item = i[1000];
      

      使用一些迭代器,您可以向后移动。

      您可以通过将迭代器与end 进行比较来发现是否超出了容器的内容:

      while (i != c.end())
      

      您可以将end 视为返回一个迭代器,该迭代器表示一个位置,该位置超出容器中的最后一个位置。

      使用迭代器(通常在 C++ 中)需要注意的重要一点是它们可能会变得无效。例如,如果您清空一个容器,通常会发生这种情况:任何指向该容器中位置的迭代器现在都变得无效。在那种状态下,对它们的大多数操作都是未定义的——任何事情都可能发生!

      【讨论】:

        【解决方案4】:

        迭代器对于 STL 容器就像指针对于数组一样。您可以将它们视为指向 STL 容器的指针对象。作为指针,您可以将它们与指针符号一起使用(例如*iElementLocatoriElementLocator++)。作为对象,它们将有自己的属性和方法(http://www.cplusplus.com/reference/std/iterator)。

        【讨论】:

          【解决方案5】:

          已经有很多关于迭代器的很好的解释。谷歌一下就行了。

          一个example

          如果您有不明白的具体内容,请回来询问。

          【讨论】:

          【解决方案6】:

          我建议阅读 C++ 中的运算符重载。这将说明为什么*-&gt; 可以意味着任何东西。只有这样你才应该阅读迭代器。否则它可能看起来很混乱。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-29
            • 1970-01-01
            • 2018-05-31
            • 2016-04-18
            • 2012-03-16
            • 2012-07-20
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多