标准模板库列表-双链接还是循环链接? 我刚刚注意到了STD:C++中的列表类,我觉得好奇。简单地说,它涉及列表迭代器的工作方式。考虑下面的代码: std::list<int> alist; alist.push_back(0); alist.push_back(1); alist.push_back(2);

标准模板库列表-双链接还是循环链接? 我刚刚注意到了STD:C++中的列表类,我觉得好奇。简单地说,它涉及列表迭代器的工作方式。考虑下面的代码: std::list<int> alist; alist.push_back(0); alist.push_back(1); alist.push_back(2);,c++,list,stl,iterator,C++,List,Stl,Iterator,显然,这会创建一个包含三个整数元素的列表。我可以在列表的开头定义一个迭代器,并使用它打印第一个元素中包含的值,如下所示: std::list<int>::iterator iter = alist.begin(); std::cout << *iter << std::endl; // Prints "0" to stdout 我发现有点奇怪的是,如果我现在减少迭代器,它会循环并最终指向列表中的最后一个元素: --iter; std::cout <&

显然,这会创建一个包含三个整数元素的列表。我可以在列表的开头定义一个迭代器,并使用它打印第一个元素中包含的值,如下所示:

std::list<int>::iterator iter = alist.begin();
std::cout << *iter << std::endl;  // Prints "0" to stdout
我发现有点奇怪的是,如果我现在减少迭代器,它会循环并最终指向列表中的最后一个元素:

--iter;
std::cout << *iter << std::endl;  // Prints "2" to stdout
对于被认为实现为双链表的东西来说,这种行为合理吗?如果列表是循环链表,我很希望迭代器也会有类似的行为,但我觉得这很奇怪

您在过去使用过的迭代器行为有什么实际用途吗?我是否应该留意与这种行为相关的任何陷阱


顺便说一句,GCC4.7.0 MinGW就是这样。我没有用任何其他版本或编译器测试过它。

在begin之后递减迭代器会调用未定义的行为。你所看到的行为很可能是巧合,看看不同的编译器会发生什么


如果你想确认这一点,你可以简单地看一下GCC列表的实现情况;通常可以在/usr/include/c++/4.x.y/bits/stl_list.h找到源代码。

在begin之后递减迭代器会调用未定义的行为。你所看到的行为很可能是巧合,看看不同的编译器会发生什么


如果你想确认这一点,你可以简单地看一下GCC列表的实现情况;您通常可以在/usr/include/c++/4.x.y/bits/stl_list.h.找到源代码。

我认为您得到的2是列表中的常量2。push_back2;。
我认为你的程序很短很简单,对吗?

我认为你得到的2是列表中的常数2;。
我认为你的程序非常简短,对吗?

看着stl_list.h,我注意到了以下评论:

   *
   *  Second, a %list conceptually represented as
   *  @code
   *    A <---> B <---> C <---> D
   *  @endcode
   *  is actually circular; a link exists between A and D.  The %list
   *  class holds (as its only data member) a private list::iterator
   *  pointing to @e D, not to @e A!  To get to the head of the %list,
   *  we start at the tail and move forward by one.  When this member

这在gcc第4.2.1条中找到。这不会改变@Oli提供的答案,因为它恰好是gcc 4.2.1中实现的答案。我会指望这个功能

看看stl_list.h,我注意到了以下评论:

   *
   *  Second, a %list conceptually represented as
   *  @code
   *    A <---> B <---> C <---> D
   *  @endcode
   *  is actually circular; a link exists between A and D.  The %list
   *  class holds (as its only data member) a private list::iterator
   *  pointing to @e D, not to @e A!  To get to the head of the %list,
   *  we start at the tail and move forward by one.  When this member

这在gcc第4.2.1条中找到。这不会改变@Oli提供的答案,因为它恰好是gcc 4.2.1中实现的答案。我会指望它的功能

它可以打印我的1218668059它可以打印我的1218668059谢谢。阅读资料有助于很好地澄清问题。谢谢你给ideone的链接-以前没见过!实际上,我已经在一些实现中看到了使用隐藏节点来闭合圆。使用该保护可以更容易地实现其余操作,插入/擦除不需要特殊情况下列表的开头/结尾,它们可以只在node->last和node->next上操作,但是在实现中调用它们时知道它引用了有效的对象。谢谢。阅读资料有助于很好地澄清问题。谢谢你给ideone的链接-以前没见过!实际上,我已经在一些实现中看到了使用隐藏节点来闭合圆。该保护的使用允许更容易地执行其余操作,插入/擦除不需要在列表的开始/结束处设置特殊情况,它们可以只在node->last和node->next上进行操作,但是在实现中调用它们时,知道它引用了一个有效的对象。该注释对实现有点误导。在该版本的STL中,列表的实现定义了仅包含指针的节点基类型,以及扩展节点基并包含实际数据的节点实现。该列表包含一个节点基实例,它关闭了循环,顺便说一句,结束迭代器。区别在于关闭列表的链接不能是保存数据的节点,否则就不可能执行最简单的循环。该注释在实现方面有点误导。在该版本的STL中,列表的实现定义了仅包含指针的节点基类型,以及扩展节点基并包含实际数据的节点实现。该列表包含一个节点基实例,它关闭了循环,顺便说一句,结束迭代器。区别在于关闭列表的链接不能是保存数据的节点,否则就不可能执行最简单的循环。