我打算写这样的代码:
std::list<whatevertype> mylist;
// ...
std::list<whatevertype>::iterator it;
for(it = mylist.begin(); it != mylist.end(); ++it) {
// ...
if(some condition)
mylist.erase(it);
}
但我意识到,此代码错误:mylist.erase(x)
会使迭代器it
无效,因此++it
可能会失败。
所以我尝试将其更改为
std::list<whatevertype>::iterator it;
std::list<whatevertype>::iterator nextit;
for(it = mylist.begin(); it != mylist.end(); it = nextit) {
// ...
nextit = it + 1;
if(some condition)
mylist.erase(it);
}
但是,令我惊讶的是,这失败了:显然operator+
没有为std::list
迭代器定义。
我已经找到了this other question并且了解到了从&#34;中删除&#34;的标准习惯用法。迭代器更像是
for(it = mylist.begin(); it != mylist.end(); ) {
if(some condition)
it = mylist.erase(it);
else ++it;
}
我相信我也可以逃脱
for(it = mylist.begin(); it != mylist.end(); ) {
// ...
std::list<whatevertype>::iterator previt = it;
++it;
if(some condition)
mylist.erase(previt);
}
但我的问题是,是否有理由没有为这些迭代器定义operator+
?
答案 0 :(得分:10)
他们对std迭代器和集合的一个规则就是让昂贵的东西变得冗长。
在列表迭代器上,it+50
需要O(50)时间。在向量迭代器上,it+50
需要O(1)时间。所以他们在向量迭代器(以及其他随机访问迭代器)上实现了+
,但在列表迭代器(以及其他较弱的迭代器)上实现了。{/ p>
std::next
以及std::advance
和std::prev
可以更轻松地解决您的问题:
auto previt = std::prev(it);
或
auto nextit = std::next(it);
这些也需要计算,但因为它们是一个明确的函数调用,所以决定它们的价格昂贵是可以接受的。
除此之外,您可以搜索以获取对std::next
和std::prev
的调用并获取迭代器操作; +
严重超载,找到昂贵的电话很难。
请注意,std::basic_string
并未遵循与其他std
容器相同的约定。
答案 1 :(得分:4)
并非所有迭代器都缺少+
。 std::list
迭代器缺少它。
这是因为列表迭代器在随机访问时非常低效。因此,随意访问是一个坏主意。
您可以使用std::advance
。它使您更清楚地一次在列表中移动一个元素。
答案 2 :(得分:3)
std :: list使用BidirectionalIterator,它只定义增量和减量。由于std :: list是一个链表,迭代器的实现一次只能移动一个节点。
该接口旨在确保您知道通过多个元素移动不是一个简单的操作,就像使用其他迭代器一样,例如从std :: vector返回的RandomAccessIterator。
请参阅http://en.cppreference.com/w/cpp/concept/Iterator以获取不同迭代器类型的定义。