根据我发现的一些STL文档,在std :: list中插入或删除元素不会使迭代器失效。这意味着允许循环遍历列表(从begin()
到end()
),然后使用push_front添加元素。
,例如,在下面的代码中,我使用元素a,b和c初始化一个列表,然后遍历它并执行元素的push_front。结果应该是cbaabc,这正是我得到的:
std::list<std::string> testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
for (std::list<std::string>::iterator itList = testList.begin(); itList != testList.end(); ++itList)
testList.push_front(*itList);
for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList)
std::cout << *itList << std::endl;
当我使用反向迭代器(从rbegin()
循环到rend()
)并使用push_back时,我会期望类似的行为,即abccba的结果。但是,我得到了不同的结果:
std::list<std::string> testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
for (std::list<std::string>::reverse_iterator itList = testList.rbegin(); itList != testList.rend(); ++itList)
testList.push_back(*itList);
for (std::list<std::string>::const_iterator itList = testList.begin(); itList != testList.end(); ++itList)
std::cout << *itList << std::endl;
结果不是abccba
,而是abcccba
。这是正确的,还有一个额外的c。
看起来第一个push_back也改变了用rbegin()初始化的迭代器的值。在push_back之后,它不再指向列表中的第3个元素(之前是最后一个元素),而是指向第4个元素(现在是最后一个元素)。
我使用Visual Studio 2010和GCC对此进行了测试,两者都返回相同的结果。
这是一个错误吗?或者反向迭代器的一些奇怪的行为,我不知道?
答案 0 :(得分:15)
标准说在插入过程中迭代器和引用仍然有效。它没有说反向迭代器。 : - )
reverse_iterator
返回的rbegin()
在内部保留end()
的值。在push_back()
后,此值显然与之前不同。我不认为标准说它应该是什么。明显的替代方案包括列表的前一个最后一个元素,或者如果它是一个固定值(如哨兵节点),它会保留在最后。
技术详细信息:rend()
返回的值无法指向begin()
之前,因为它无效。因此决定rend()
应该包含begin()
的值,并且所有其他反向迭代器将进一步移位一个位置。 operator*
会对此进行补偿,并且无论如何都会访问正确的元素。
24.5.1反向迭代器的第一段说:
类模板
reverse_iterator
是一个迭代器适配器,它从定义的序列的末尾开始迭代 通过它的底层迭代器到该序列的开头。反向之间的基本关系 迭代器及其相应的迭代器我是由身份建立的:
&*(reverse_iterator(i)) == &*(i - 1)
。
答案 1 :(得分:7)
我想要理解这一点,最好先将for
循环重新转换为while
循环:
typedef std::list<std::string> container;
container testList;
testList.push_back("a");
testList.push_back("b");
testList.push_back("c");
container::reverse_iterator itList = testList.rbegin();
while (itList != testList.rend()) {
testList.push_back(*itList);
++itList;
}
除此之外,我们还必须了解reverse_iterator
的工作原理。具体来说,reverse_iterator
确实指向了之后的元素,当你取消引用它时,它就是。 end()
在容器结束之后只产生的迭代器 - 但对于像数组这样的东西,没有定义的方法指向容器的开头之前。相反,C ++所做的就是让迭代器从结束后开始,然后进行到开始,但是当你取消引用它时,你只需要之前的元素实际指向它。
这意味着您的代码实际上是这样的:
在那之后,你得到了你所期望的,推回B然后A,所以你最终得到了ABCCCBA。
答案 2 :(得分:0)
尝试为两者使用迭代器。试试:
std::list<std::string>::iterator i = testList.end();
并使用--i
反转