我正在阅读别人的代码,他们分别在循环内增加for循环计数器,以及包括通常的事后想法。例如:
for( int y = 4; y < 12; y++ ) {
// blah
if( var < othervar ) {
y++;
}
// blah
}
基于其他人编写和阅读的大部分代码,我应该期待看到这个吗?
答案 0 :(得分:31)
在 for 循环中操作循环计数器的做法并不十分普遍。阅读该代码的人会感到惊讶。并且令人惊讶您的读者很少是一个好主意。
对循环计数器的额外操作会给代码增加吨的复杂性,因为您必须牢记它的含义以及它如何影响循环的整体行为。正如Arkady所说,它使您的代码更难维护。
简单地说,避免使用此模式。当你遵循“清洁代码”原则,特别是single layer of abstraction (SLA)原则时,就没有
这样的东西for(something)
if (somethingElse)
y++
遵循该原则要求您将if
块移动到其自己的方法中,使得在该方法中操纵某些外部计数器变得尴尬。
但除此之外,可能会出现像你的例子那样“某事”的情况;但是对于那些情况 - 为什么不在循环中使用呢?
换句话说:使您的示例变得复杂和混乱的事实是,代码的两个不同部分会改变您的循环计数器。所以另一种方法可能如下:
while (y < whatever) {
...
y = determineY(y, who, knows);
}
然后,新方法可以成为计算如何更新循环变量的中心位置。
答案 1 :(得分:27)
我不同意上述广受好评的答案。在循环体内操纵循环控制变量没有任何问题。例如,这是清理地图的经典示例:
for (auto it = map.begin(), e = map.end(); it != e; ) {
if (it->second == 10)
it = map.erase(it);
else
++it;
}
因为我已经正确地指出了迭代器与数字控制变量不同的事实,所以让我们考虑一个解析字符串的例子。让我们假设字符串由一系列字符组成,其中字符前缀为&#39; \&#39;被认为是特殊的,需要跳过:
for (size_t i = 0; i < s_len; ++i) {
if (s[i] == '\\') {
++i;
continue;
}
process_symbol(s[i]);
}
答案 2 :(得分:10)
改为使用while循环。
虽然可以使用for循环执行此操作,但 不应该。请记住,程序就像任何其他通信一样,必须考虑到您的受众。对于一个程序,观众包括编译器和下一个对代码进行维护的人(可能在大约6个月内)。
对编译器来说,代码非常直观 - 设置索引变量,运行循环体,执行增量,然后检查条件以查看是否再次循环。编译器不关心你是否使用循环索引。
然而,对于某个人来说,for循环具有特定的隐含含义:运行此循环固定次数。如果你使用循环索引,那么这就违反了这个含义。从某种意义上讲它是不诚实的,这很重要,因为下一个阅读代码的人要么花费额外的精力来理解循环,要么就是不能这样做,因此无法理解。
如果你想使用循环索引,请使用while循环。特别是在C / C ++ /相关语言中,for循环和while循环一样强大,所以你永远不会失去任何力量或表现力。任何for循环都可以转换为while循环,反之亦然。但是,下一个阅读它的人将不会依赖于你没有使用循环索引的暗示。使它成为while循环而不是for循环是一种警告,这种循环可能更复杂,在你的情况下,它实际上更复杂。
答案 3 :(得分:7)
如果在循环内增加,请务必对其进行注释。 Q&amp; A How to remove from a map while iterating it?(逐字代码副本)中提供了一个规范示例(基于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;
}
}
这里,end()
迭代器的非常数性质和循环内部的增量都是令人惊讶的,因此需要记录它们。注意:此处的循环提升毕竟是可能的,因此可能应该为代码清晰完成。
答案 4 :(得分:3)
对于它的价值,以下是C ++核心指南对此主题的评论:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-loop-counter
ES.86:避免修改raw体内的循环控制变量 for-loops
原因预先的循环控制应该启用正确 推理循环内发生的事情。修改循环 迭代表达式和体内的计数器 循环是一个常年的惊喜和错误来源。
另请注意,在这里讨论std::map
的情况的其他答案中,控制变量的增量仍然只在每次迭代中完成一次,在您的示例中,每次迭代可以执行多次
答案 5 :(得分:3)
所以在一些混乱之后,即关闭,重新开启,问题正文更新,标题更新,我认为问题终于明确了。并且不再基于意见。
据我所知,问题是:
当我查看其他人编写的代码时,我是否应该期待看到&#34;循环条件变量&#34;在循环体中被改变了吗?
答案很清楚:
当您使用其他代码时 - 无论您是否进行审核,修复错误,添加新功能 - 您都应该期待最坏的情况。
在语言中有效的一切都是可以预期的。
不要对任何良好做法的代码做出任何假设。
答案 6 :(得分:2)
写作while循环真的更好
y = 4;
while(y < 12)
{
/* body */
if(condition)
y++;
y++;
}
您有时可以将循环逻辑从正文中分离出来
while(y < 12)
{
/* body */
y += condition ? 2 : 1;
}
当且仅当你很少&#34;跳过&#34;我会允许for()方法。一个物品, 比如带引号的字符串中的转义。