Как работает итератор внутри C ++? - PullRequest
1 голос
/ 01 марта 2020

Я не могу понять, как итератор работает именно в C ++. Как я читал в некоторых блогах, этот итератор не содержит адреса. Если он не содержит адреса, то как именно мы увеличиваем его, например it++ или ++it.

Давайте рассмотрим пример итератора вектора.

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

, если итератор не указатель, содержащий адрес, тогда что именно делает ++. Что это хранит. Как это работает внутри. Как итератор точно указывает на элементы вектора?

1 Ответ

2 голосов
/ 01 марта 2020

Если мы не можем предположить, что итератор является указателем, это не означает, что итератор не может внутренне полагаться на указатель.
Итератор может рассматриваться как метафора указателя ( что мы можем увеличивать, разыменовывать ...), а затем в некоторых случаях (массив, вектор) этот итератор может быть просто сделан из указателя на элементы (не обязательно быть именно этим указателем, а скорее структурой с таким указателем как данные членом).

Основным преимуществом является то, что все детали скрыты внутри этой метафоры , и в тривиальных случаях (например, вектор в следующем примере) она ведет себя точно так, как если бы мы фактически использовали указатель, но в других случаях (например, список в следующем примере) он делает что-то, вероятно, совсем другое.
Нам не нужно об этом беспокоиться, мы просто пишем код таким же образом, и мы можем даже написать generi c код, который ведет себя соответствующим образом.

Обратите внимание, что явное использование итераторов в следующем примере разрешено здесь, чтобы соответствовать вашему первоначальному вопросу; было бы лучше положиться на циклы диапазона в реальном коде.

/**
  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;
}
...