【问题标题】:Inserting to std::list using reverse iterator changes the value of the original reverse iterator使用反向迭代器插入到 std::list 会更改原始反向迭代器的值
【发布时间】:2013-12-03 02:52:15
【问题描述】:

已经在网上搜索了很多,但找不到问题的答案。

我正在使用它的 reverse_iterator 向 std::list 插入一个值。虽然插入按预期发生在适当的位置,但我注意到用于插入的原始 reverse_iterator 的值发生了变化。完全不相关的 reverse_iterator 的值也会发生变化。我已经能够在一个简单的例子中重现这一点

#include <iostream>
#include <list>
#include <string>

int main()
{
    // Creating a list of values 1, 2, 4, 5
    std::list<int> myList;
    myList.push_back(1);
    myList.push_back(2);
    myList.push_back(4);
    myList.push_back(5);

    // Changing it to 1, 2, 3, 4, 5 by inserting 3
    std::list<int>::reverse_iterator revIter = myList.rbegin();
    while(2 != *revIter)
    {
        std::cout << *revIter << "\t";
        ++revIter;
    }

    std::cout << "\n" << "Reverse iterator now points to " << *revIter;
    // Creating a copy of the reverse Iter before inserting.
    std::list<int>::reverse_iterator newRevIter = revIter;
    myList.insert(revIter.base(), 3);

    // Checking the values of revIter and newRevIter 
    std::cout << "\n" << "Reverse Iterator now points to " << *revIter; // UNEXPECTED RESULT HERE
    std::cout << "\n" << "New Reverse Iterator now points to " << *newRevIter; // UNEXPRECTED RESULT HERE

    std::cout << "\n" << "Printing final list:" << "\n";
    for(std::list<int>::iterator iter = myList.begin(); myList.end() != iter; ++iter)
    {
        std::cout << *iter << "\t"; // Results are fine
    }

    return 0;
}

结果

5    4
Reverse iterator now points to 2
Reverse iterator now points to 3
New Reverse iterator now points to 3
Printing final list:
1    2    3    4    5

这是预期的行为。如果是这样,如何使用反向迭代器将项目插入列表(或者在这方面它没用)?

【问题讨论】:

  • 请注意:“复制”迭代器很像复制指针。 (请注意,您以完全相同的方式“取消引用”它们)。因此,当您取消引用 revIter 和 newRevIter 时,它们产生相同的值是完全正常的。
  • 不确定标准是怎么说的,但这使用插入的返回值应该可以工作,revIter = std::list&lt;int&gt;::reverse_iterator(myList.insert(revIter.base(), 3));
  • @JBL。是的,我知道。我只是想确保我没有犯任何错误。反向迭代器指向的值确实在变化。
  • @john。谢谢,这似乎工作。你能进一步解释它为什么起作用吗?
  • @john_zac David 下面的回答解释了如何实现反向迭代器。 list::insert 返回新插入的节点,通过创建一个反向迭代器,您实际上得到一个反向迭代器,它引用新插入节点之前的节点。

标签: c++ stdlist reverse-iterator


【解决方案1】:

我会避免使用反向迭代器(一般来说,特别是除了顺序横向之外的任何东西)。正向和反向迭代器的工作方式不同,在正向迭代器进入列表的情况下,迭代器跟踪您通过operator* 访问的节点,但在反向情况下,迭代器跟踪列表中的下一个元素。取消引用反向迭代器的行为获取迭代器引用的节点的前驱并从中提取值。图形化(f 是正向迭代器,r 是反向迭代器)

  f
1 2 4
    r

正向迭代器 f 和反向迭代器 r 在取消引用时都会产生 2,但它们跟踪的节点不同。当您使用 r 插入时,您在 2 和 4 之间插入,但底层迭代器仍然指向持有 4 的节点:

  f
1 2 3 4
      r

现在,如果您取消引用 r,则适用与上述相同的过程。获取当前节点的前任,并打印值,只是现在4的前任是3,这就是你得到的。

这是预期的行为。如果是这样,如何使用反向迭代器将项目插入列表(或者在这方面它没用)?

是的,这是预期的行为。如何使用反向迭代器将项目插入列表?了解它的工作原理。

【讨论】:

  • +1 谢谢,现在说得通了。我并没有像最初那样深入分析它。它还解释了约翰的评论。
【解决方案2】:

插入后的不变量是std::reverse_iterator&lt;&gt;::base(),而不是std::reverse_iterator&lt;&gt; 本身。但是,与reverse_iterator 相比,base() 确实针对先前的元素:

http://en.cppreference.com/w/cpp/iterator/reverse_iterator

让我有点困扰的是,当我将std::distance 转换为begin()(或rend().base())时:

  std::cout << "\n" 
        << "Reverse Iterator now points to " 
        << *revIter << "-" << *(revIter.base())<< "-" 
        << std::distance(revIter.base(), myList.rend().base()); 

我有:

反向迭代器现在指向 2-4-3

反向迭代器现在指向 3-4-3

或者我希望第二个是“3-4-4”,因为元素是在base()...之前插入的...

【讨论】:

    猜你喜欢
    • 2012-04-22
    • 2010-10-27
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多