列表迭代器参考 - 程序输出

问题描述

给定以下算法:

#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist = {5,10,15,20};

  std::cout << "mylist contains:"<<"\n";

  //for (auto it = mylist.begin(); it != mylist.end(); ++it)
  auto it = mylist.begin();
  while ( it != mylist.end())
  {
      std::cout << *it;
      std::cout << "    "<< &it<<std::endl;
      it++;
  }

  std::cout << '\n';

  return 0;
}

这个程序的输出是:

mylist contains:
 5     0x7dc9445e5b50
 10    0x7dc9445e5b50
 15    0x7dc9445e5b50
 20    0x7dc9445e5b50

既然我们移动了迭代器,为什么地址没有改变?

我排除了引用的 4 字节偏移量。

解决方法

试试这个:

  std::cout << "    "<< &*it<<std::endl;

阅读本文以了解传统双向迭代器的描述。

https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator

从本文档中可以看出这一点并不是很明显,但是对于这个迭代器和整个 STL 中的迭代器,运算符 *() 将返回:

  T & operator *();

  const T & operator *() const; // for const iterators (list iterator in this case).

我希望这比我之前的简洁回答更具说明性。

,

您的问题很简单:it 是一个变量。现在,您正在打印该变量的地址。您为该变量分配了不同的,但该变量在其存在的整个过程中都存储在内存中的同一位置,因此当您打印出其地址时,您每次都会看到相同的值。

您想要做的是打印出存储在该变量中的值——迭代器引用的对象的地址。就迭代器而言,这样做可能有些棘手,因为迭代器是一种抽象——根据设计,您并不真正知道它包含什么。

然而,我们可以相当可靠地猜测关于 std::list 的迭代器可能是如何实现的。特别是,它可能是这样的:

template <class T>
class iterator {
    T *data;
public:
    T &operator*() { return *data; }

    // ... and many more functions we don't care about for now
};

这里的重点是,尽管 it 可能会存储不同的数据以产生其结果,但 operator* 需要返回对迭代器所引用对象的引用。因此,为了获取(至少有效地)存储在迭代器中的地址,我们可以使用 operator* 获取对对象的引用,然后使用 & 获取地址那个对象。

缺点:虽然这会告诉您迭代器在不同时间引用的对象的地址,但它不一定会告诉您迭代器本身真正包含什么。只要迭代器从指定的操作中产生正确的结果,迭代器基本上可以以任何它认为合适的方式自由地产生它们(但也就是说,对于 std::list 的迭代器,是的,它可能会使用指针)。