如果list为空,则std list reverse-iterator的past-the-end迭代器失效

时间:2016-10-28 03:00:05

标签: c++ list iterator

如果修改列表并且列表为空,则std :: list的反向past-end迭代器将失效。但是根据语言规范列表,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

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

`

1 个答案:

答案 0 :(得分:0)

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

一般来说,反向迭代器有一个基数&#34; normal&#34;迭代器。反向迭代器引用的元素不是基础引用的元素,而是基础迭代器元素之前的元素。 (这是因为在开始之前没有迭代器)

rendreverse(begin)。在空列表中begin==end。因此rendreverse(end)

插入列表时,没有迭代器失效。您的rend副本仍为reverse(end),但再次致电rend会返回reverse(begin)。他们不再平等。

对我而言,这似乎令人惊讶,但我认为它是合规的。 C ++标准无法合理地避免这个&#34; bug&#34;。