【问题标题】:How does an iterator works internally in C++?迭代器如何在 C++ 内部工作?
【发布时间】:2020-06-13 22:57:40
【问题描述】:

我无法理解迭代器在 C++ 中是如何工作的。正如我在一些博客中读到的,迭代器不包含地址。如果它不包含地址,那么我们如何准确地增加它,例如 it++++it

让我们举一个向量迭代器的例子。

vector<int> ::iterator it;
for(it=vec.begin(); it!=vec.end(); it++)
{
    // do something
}

如果迭代器不是包含地址的指针,那么它++到底在做什么。它在存储什么。它是如何在内部工作的。迭代器如何准确指向向量的元素?

【问题讨论】:

  • 你似乎没有代码问题,而是一些关于 C++ 的通用问题。
  • 你知道什么是运算符重载吗?
  • "如果迭代器不是包含地址的指针",从技术上讲,指针对于std::vector 来说是非常有效的迭代器(并且可能在大多数 C++ 标准库中使用实现),但它也可以是为此而设计的类。
  • @Yksisarvinen 我不认为任何主要的标准库实现都使用 std::vector 迭代器 (godbolt.org/z/t5NhEp) 的指针。
  • @pujadeo 如上所述,一个简单的指针对于std::vector 迭代器也是有效的,但我假设大多数实现都会向迭代器类添加可选的越界检查等。对于其他容器,例如std::list,指针是不够的,因为元素不是连续存储的,因此运算符重载的类例如找到正确的下一个元素是必要的。迭代器概念是指针概念的推广。

标签: c++ c++11 vector stl iterator


【解决方案1】:

如果我们不能假设迭代器是指针,这并不意味着 迭代器不能在内部依赖指针。
迭代器可以被认为是指针的隐喻(我们可以 增量,取消引用...),然后在某些情况下(数组,向量)这个迭代器 可以简单地由指向元素的指针组成(不一定完全是 this 指针,而是一个以这样的指针作为数据成员的结构)。

主要优点是所有细节都隐藏在这个隐喻中 在微不足道的情况下(如以下示例中的向量),它的行为 就像我们实际上使用了指针一样,但在其他情况下(比如列表 在下面的示例中)它可能会做一些非常不同的事情。
我们不必为此烦恼,我们只需以相同的方式编写代码, 我们甚至可以编写相应行为的通用代码。

请注意,以下示例中迭代器的显式用法是 让这里匹配您最初的问题;最好依靠 实际代码中的 range-for 循环。

/**
  g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
      -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <iostream>
#include <vector>
#include <list>

template<typename T>
void
display(const char *title,
        const T &container)
{
  using std::cbegin;
  using std::cend;
  std::cout << title;
  for(auto it=cbegin(container); it!=cend(container); ++it) // range-for would be better
  {
    std::cout << ' ' << *it;
  }
  std::cout << '\n';
}

int
main()
{
  const auto v=std::vector<int>{10, 20, 30, 40, 50};
  const auto l=std::list<int>{10, 20, 30, 40, 50};
  //
  std::cout << "specific v:";
  for(auto it=cbegin(v); it!=cend(v); ++it) // range-for would be better
  {
    std::cout << ' ' << *it;
  }
  std::cout << '\n';
  //
  std::cout << "specific l:";
  for(auto it=cbegin(l); it!=cend(l); ++it) // range-for would be better
  {
    std::cout << ' ' << *it;
  }
  std::cout << '\n';
  //
  display("generic v:", v);
  display("generic l:", l);
  return 0;
}

【讨论】:

    猜你喜欢
    • 2016-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 2021-09-05
    • 2012-08-28
    相关资源
    最近更新 更多