假设我有一个vector<int> myvec
,我想反过来遍历所有元素。我可以想到几种方法:
for (vector<int>::iterator it = myvec.end() - 1; it >= myvec.begin(); --it)
{
// do stuff here
}
for (vector<int>::reverse_iterator rit = myvec.rbegin(); rit != myvec.rend(); ++rit)
{
// do stuff here
}
for (int i = myvec.size() - 1; i >= 0; --i)
{
// do stuff here
}
所以我的问题是我什么时候应该使用它们?有区别吗?我知道第一个是危险的,因为如果我传入一个空的向量,那么myvec.end() - 1
是未定义的,但是这还有其他危险或效率低下吗?
答案 0 :(得分:11)
reverse_iterator
版本显示意图并适用于所有容器,无论其内容如何。
第一个有你描述的缺陷。它还使用>=
,这对非随机访问迭代器不起作用。
第三个问题是i
是int
。它将无法保持size()
可能返回的数量。使其无符号工作(vector<int>::size_type
),但我们遇到与解决方案一样的问题。 (0U - 1
- &gt; Funky terminating checks
- &gt; :|
)
答案 1 :(得分:7)
一般都不是以上。相反,你通常应该高枕无忧几秒钟,找出你想要应用的算法,而忘记自己编写一个循环。您可能会使用reverse_iterator
,但根据您要完成的操作并非总是如此(例如,请参阅std::copy_backwards
)。
答案 2 :(得分:3)
就个人而言,我会选择第二个。
正如您所指出的那样,第一个要求您将循环包装在if (!myvec.empty())
中以避免未定义的行为。
对于最后一个,您应该使用vector<int>::size_type
或size_t
,在这种情况下>= 0
是错误的,您需要执行!= (size_t)-1
或类似操作
reverse_iterator
版本更清晰。
答案 3 :(得分:2)
对于第一个版本,你也不可避免地会在循环结束时递减begin()
迭代器(未定义的行为)。
reverse_iterator
是为此做的。
如果您使用更有争议的形式,第三种方法可能会更好一些:
for (size_t i = vec.size(); i --> 0; )
如果人们停止抗拒,这可能是一个成语。它使用合适的计数器类型(无符号),并包含助记符,便于记忆和识别。
答案 4 :(得分:1)
始终使用第二个。第一个你排除了自己,第三个不适用于列表等。
答案 5 :(得分:1)
有第四种选择(不一定是一个好的选择,但它存在)。您可以以模仿反向迭代器实现方式的方式使用双向/随机访问迭代器,以避免空迭代器上myvec.end()-1
的问题:
for (vector<int>::iterator it = myvec.end(); it != myvec.begin(); --it)
{
// convert the loop controlling iterator to something that points
// to the item we're really referring to
vector<int>::iterator true_it = it;
--true_it;
// do stuff here
// but always dereference `true_it` instead of `it`
// this is essentially similar to the way a reverse_iterator
// generally works
int& x = *true_it;
}
甚至:
for (vector<int>::iterator it = myvec.end(); it != myvec.begin();)
{
// decrement `it` before the loop executes rather than after
// it's a bit non-idiomatic, but works
--it;
int& x = *it;
// do stuff...
}
就像我说的那样,这不一定是一个好的选择(我认为Jerry Coffin's answer是你应该首先考虑的方法),但我认为它很有意义,因为它显示了反向迭代器如何在幕后工作 - 以及它避免了将reverse_iterator转换为迭代器的时间,因为你可能希望将迭代器用于不接受reverse_iterator
的事情(将reverse_iterator
转换为iterator
s似乎让我头疼,所以我经常会避免reverse_iterators
以避免头痛。例如,如果要为该位置调用insert(),则反向迭代器引用:
// if `it` is a reverse iterator, a call to insert might have to look something like:
myvec.insert( --(it.base()), 42 ); // assume that you know the current vector capacity
// will avoid a reallocation, so the loop's
// iterators won't be invalidated
// if `it` is a normal iterator...
myvec.insert( it, 42 );