问题描述
给定以下算法:
#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
的迭代器,是的,它可能会使用指针)。