vol*_*vox 16 language-agnostic for-loop loop-counter
我正在读别人的代码,他们分别在循环内增加for循环计数器,以及包括通常的事后想法.例如:
for( int y = 4; y < 12; y++ ) {
// blah
if( var < othervar ) {
y++;
}
// blah
}
Run Code Online (Sandbox Code Playgroud)
根据其他人编写和阅读的大部分代码,我应该期待看到这个吗?
Gho*_*ica 31
在for循环中操作循环计数器的做法并不十分普遍.阅读该代码的人会感到惊讶.而令人惊讶你的读者是很少一个好主意.
你的循环计数器的额外的操作增加了吨的复杂性,以你的代码,因为你必须牢记这意味着什么,它是如何影响环路的整体行为.正如Arkady所说,它使您的代码更难维护.
简单地说,避免这种模式.当你遵循"清洁代码"原则,特别是单层抽象(SLA)原则时,就没有这样的东西
for(something)
if (somethingElse)
y++
Run Code Online (Sandbox Code Playgroud)
遵循该原则要求您将该if块移动到其自己的方法中,使得在该方法中操纵某些外部计数器变得尴尬.
但除此之外,可能会出现像你的例子那样"某事"的情况; 但对于那些情况 - 为什么不使用while循环呢?
换句话说:使您的示例变得复杂和混乱的事实是代码的两个不同部分改变了循环计数器.所以另一种方法可能如下:
while (y < whatever) {
...
y = determineY(y, who, knows);
}
Run Code Online (Sandbox Code Playgroud)
那么这个新方法可以成为计算如何更新循环变量的中心位置.
Ser*_*eyA 27
我不同意上面广为人知的答案.在循环体内操纵循环控制变量没有任何问题.例如,以下是清理地图的经典示例:
for (auto it = map.begin(), e = map.end(); it != e; ) {
if (it->second == 10)
it = map.erase(it);
else
++it;
}
Run Code Online (Sandbox Code Playgroud)
因为我已经正确地指出了迭代器与数字控制变量不同的事实,让我们考虑一个解析字符串的例子.假设字符串由一系列字符组成,其中前缀为'\'的字符被认为是特殊字符,需要跳过:
for (size_t i = 0; i < s_len; ++i) {
if (s[i] == '\\') {
++i;
continue;
}
process_symbol(s[i]);
}
Run Code Online (Sandbox Code Playgroud)
小智 10
请改用while循环.
虽然您可以使用for循环执行此操作,但您不应该这样做.请记住,程序就像任何其他通信一样,必须考虑到您的受众.对于一个程序,观众包括编译器和下一个对代码进行维护的人(可能在大约6个月内).
对编译器来说,代码非常直观 - 设置索引变量,运行循环体,执行增量,然后检查条件以查看是否再次循环.编译器不关心你是否使用循环索引.
然而,对于某个人来说,for循环具有特定的隐含含义:运行此循环固定次数.如果你使用循环索引,那么这就违反了这个含义.从某种意义上说它是不诚实的,这很重要,因为下一个阅读代码的人要么花费额外的精力去理解循环,要么就是不能这样做,因此无法理解.
如果你想使用循环索引,请使用while循环.特别是在C/C++ /相关语言中,for循环和while循环一样强大,所以你永远不会失去任何力量或表现力.任何for循环都可以转换为while循环,反之亦然.但是,下一个阅读它的人将不会依赖于你没有使用循环索引的暗示.使它成为while循环而不是for循环是一种警告,这种循环可能更复杂,在你的情况下,它实际上更复杂.
如果在循环内增加,请确保对其进行注释.在问答中给出了一个典型的例子(基于Scott Meyers Effective C++项目)如何在迭代时从地图中删除?(逐字代码复印件)
for (auto it = m.cbegin(); it != m.cend() /* not hoisted */; /* no increment */)
{
if (must_delete)
{
m.erase(it++); // or "it = m.erase(it)" since C++11
}
else
{
++it;
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,end()迭代器的非常量性质和循环内部的增量都是令人惊讶的,因此需要记录它们.注意:此处的循环提升毕竟是可能的,因此可能应该为代码清晰度完成.