考虑以下两行代码:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
还有这个:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
我被告知第二种方式更受欢迎。为什么呢?
考虑以下两行代码:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
还有这个:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
我被告知第二种方式更受欢迎。为什么呢?
STL迭代器的主要作用是使STL算法(如sort)与容器无关。
如果您只想循环遍历向量中的所有条目,请使用索引循环样式。
对于大多数人来说,这样做的输入更少且更易于解析。如果C++有一个简单的foreach循环而不会过度依赖模板魔法,那就太好了。
for( size_t i = 0; i < some_vector.size(); ++i )
{
T& rT = some_vector[i];
// now do something with rT
}
'
我认为对于向量来说,使用索引和不使用索引并没有太大的区别。个人更喜欢使用索引,因为这样更易读,而且可以随意跳转到向前或向后的第6个元素。
我还喜欢在循环中引用项,就像这样,这样就不会出现很多方括号:
for(size_t i = 0; i < myvector.size(); i++)
{
MyClass &item = myvector[i];
// Do stuff to "item".
}
如果您认为将来可能需要使用列表替换向量,并且还想让STL爱好者看起来更加时尚,那么使用迭代器可能是个不错的选择,但我想不出其他理由。
在了解了这个答案的主题后,我意识到它有点过于简化了。这个循环与以下循环之间的区别:
for (some_iterator = some_vector.begin(); some_iterator != some_vector.end();
some_iterator++)
{
//do stuff
}
这个循环:
for (int i = 0; i < some_vector.size(); i++)
{
//do stuff
}
这种方式的循环语法非常简洁。事实上,我似乎越来越喜欢这种方式:
while (it != end){
//do stuff
++it;
}
迭代器确实解锁了一些强大的声明性功能,当与STL算法库结合使用时,您可以做一些非常酷的事情,这些事情超出了数组索引管理的范围。
for (Iter it = {0}; it != end; ++it) {...}
- 你只是省略了声明 - 所以简洁性与你的第二个例子并没有太大的区别。不过还是要点赞。 - Engineer索引需要额外的mul
操作。例如,对于vector<int> v
,编译器将v[i]
转换为&v + sizeof(int) * i
。
sizeof
,并且只需在每次迭代中添加一次,而不是每次都重新进行整个偏移量计算。 - underscore_dfor
循环 对您的向量(或任何其他容器)进行迭代,如下所示:for (auto &item : some_vector)
{
//do stuff
}
item
直接访问向量的元素,而不必担心弄乱索引或在解除引用迭代器时犯错误。此外,占位符auto
避免了重复容器元素类型的问题,使您更接近一个与容器无关的解决方案。operator[]
(并且足够快),那么最好使用第一种方法。for
循环不能用于向容器添加/删除元素。如果您要这样做,最好坚持Brian Matthews所提供的solution。const
:for (auto const &item : some_vector) { ... }
。在迭代过程中,您不需要知道要处理的项目数量。您只需要这个项目,而迭代器可以非常好地完成这些操作。
std::vector
)时,它们不会变得无效,因此您可以在迭代期间向容器添加项目。reserve()
,因此需要知道要附加多少项。我不使用迭代器的原因与我不喜欢foreach语句相同。当有多个内部循环时,要在不记住所有局部变量和迭代器名称的情况下跟踪全局/成员变量已经足够困难了。我发现有用的是为不同场合使用两组索引:
for(int i=0;i<anims.size();i++)
for(int j=0;j<bones.size();j++)
{
int animIndex = i;
int boneIndex = j;
// in relatively short code I use indices i and j
... animation_matrices[i][j] ...
// in long and complicated code I use indices animIndex and boneIndex
... animation_matrices[animIndex][boneIndex] ...
}
我甚至不想将"animation_matrices[i]"这样的东西缩写成一些随意命名为"anim_matrix"的迭代器,因为这样你就无法清楚地看出这个值来自哪个数组。
it
,jt
,kt
等等,甚至可以继续使用i
、j
、k
等等。如果您需要确切知道迭代器表示什么,则对我来说,像for (auto anim = anims.begin(); ...) for (auto anim_bone = anim->bones.begin(); ...) anim_bone->wobble()
这样的写法比不断索引animation_matrices[animIndex][boneIndex]
更具描述性。 - underscore_dfor
循环,这使得基于迭代器的方法更加简洁。 - underscore_d
some_iterator++
修改为++some_iterator
,则更倾向于使用第二种方式。因为后置自增会创建一个不必要的临时迭代器。 - jasonend()
加入声明子句。 - Lightness Races in Orbitvector::end
(向量的结尾) 的C++实现,可能存在比它是否被提取出循环更值得担心的问题。就我个人而言,我更喜欢清晰易懂的代码——如果终止条件中涉及到find
操作,那么我会感到有点担忧。 - Steve Jessopit != vec.end()
和it != end
,而是(vector<T>::iterator it = vec.begin(); it != vec.end(); ++it)
和(vector<T>::iterator it = vec.begin(), end = vec.end(); it != end; ++it)
。我不需要计算字符数。当然可以更喜欢其中一个,但别人对你偏好的异议并不是“粗心”,而是更喜欢变量更少、阅读时更易考虑的简化代码。 - Steve Jessop