【问题标题】:std list reverse-iterator's past-the-end iterator gets invalidated, if list is empty [duplicate]如果列表为空,std list reverse-iterator 的过去迭代器将失效[重复]
【发布时间】:2017-03-10 21:24:11
【问题描述】:

如果我修改列表并且列表为空,则 std::list 的反向过去结束迭代器将失效。但是根据语言规范列表 push_back 应该对迭代器没有影响:

将给定的元素值附加到容器的末尾。 1) 新元素被初始化为值的副本。 2) 值被移动到新元素中。 没有迭代器或引用无效。

正如我在language spec 中注意到的那样。在下面列出示例,否则我会发现该行为。

//Add or replace an element using reverse iterator
void addOrReplaceRev(std::list<int>& list, int val)
{
    auto rit = std::find(list.rbegin(), list.rend(), val);
    list.push_back(val); //invalidates the rend() iterator, if list empty
    if(rit != list.rend()) //remove if the value existed earlier
        list.erase((++rit).base());

}

void addOrReplace(std::list<int>& list, int val)
{
    auto rit = std::find(list.rbegin(), list.rend(), val);
    bool shouldErase = rit != list.rend(); //save the result before modification
    list.push_back(val);
    if(shouldErase) //All good, as we use saved query result
        list.erase((++rit).base());
}

int main()
{
    std::list<int> mylist1;
    std::list<int> mylist2 = {1,2,4,5};

    addOrReplaceRev(mylist1, 3); //empty list messes up with rev iters
    addOrReplaceRev(mylist2, 3); //non-empty lists are fine
    printf("SIZES %d:%d\n", mylist1.size(), mylist2.size());

    std::list<int> mylist3;
    std::list<int> mylist4 = {1,2,4,5};

    addOrReplace(mylist3, 3);//if results are saved
    addOrReplace(mylist4, 3);
    printf("SIZES %d:%d\n", mylist3.size(), mylist4.size());
}

程序的输出是

SIZES 0:5
SIZES 1:5

注意:当我使用正向/常规迭代器时,我看不到这种行为。我正在使用 gcc 4.9.2 编译器。这是预期的还是编译器错误。

`

【问题讨论】:

  • 尽管名称中有“iterator”,但保证适用于容器的迭代器不一定适用于其反向迭代器。

标签: c++ list iterator


【解决方案1】:

反向迭代器不是容器的迭代器,不是直接的。它们是根据容器的迭代器定义的。

一般来说,反向迭代器有一个基本的“正常”迭代器。反向迭代器所指的元素不是基类所指的元素,而是基类迭代器的元素之前的元素。 (这是因为没有迭代器 one-before-begin)

rendreverse(begin)。在一个空列表上,begin==end。所以rendreverse(end)

当您插入到列表中时,没有迭代器无效。您的rend 副本仍然是reverse(end),但再次调用rend 会返回reverse(begin)。而且他们不再平等。

对我来说,这似乎令人惊讶,但我认为它是合规的。 C++ 标准无法合理避免这个“错误”。

【讨论】:

  • @Yakk 谢谢。对于空列表,我错过了关于 beginend 相等的部分。尽管如此,正如您所说,我对这种行为感到惊讶,尤其是我们得到了空列表和非空列表的两种不同行为。
猜你喜欢
  • 2010-09-13
  • 2016-08-16
  • 2020-11-22
  • 1970-01-01
  • 1970-01-01
  • 2011-09-23
  • 1970-01-01
  • 2011-04-14
  • 2011-07-13
相关资源
最近更新 更多