如果修改列表并且列表为空,则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编译器。这是预期的还是编译器错误。
`
答案 0 :(得分:0)
反向迭代器不是容器的迭代器,不是直接的。它们是根据容器的迭代器定义的。
一般来说,反向迭代器有一个基数&#34; normal&#34;迭代器。反向迭代器引用的元素不是基础引用的元素,而是基础迭代器元素之前的元素。 (这是因为在开始之前没有迭代器)
rend
是reverse(begin)
。在空列表中begin==end
。因此rend
为reverse(end)
。
插入列表时,没有迭代器失效。您的rend
副本仍为reverse(end)
,但再次致电rend
会返回reverse(begin)
。他们不再平等。
对我而言,这似乎令人惊讶,但我认为它是合规的。 C ++标准无法合理地避免这个&#34; bug&#34;。