【问题标题】:Any reason to replace while(condition) with for(;condition;) in C++?有什么理由在 C++ 中用 for(;condition;) 替换 while(condition)?
【发布时间】:2010-11-25 15:22:42
【问题描述】:

看起来像

while( condition ) {
    //do stuff
}

完全等价于

for( ; condition; ) {
    //do stuff
}

有什么理由使用后者而不是前者?

【问题讨论】:

  • 两个示例代码都是正确的并且做同样的事情。但是没有理由使用第二个语句。当有正确的语法可用时,为什么要使用第二个。那么使用第二个语句的唯一原因是要了解不同类型的代码,我认为它应该只用于教育目的。
  • 我在一个项目中看到了后者,想知道它可能出现的原因。
  • 人们对风格的看法不同,而且常常是截然不同的,而且常常以我意想不到的方式。出于某种当时似乎有道理的原因,有人可能想对所有循环的 for 语句进行标准化。没有功能上的区别。
  • 我能想到的唯一原因是代码会随着时间而变化。也许循环开始时是一个普通的 for 循环,然后被更改了几次,删除了第一部分和最后一部分。而做它的程序员只是没想到把它改成一个while循环。
  • @David:看来意见的热度与问题的重要性成反比。

标签: c++ loops for-loop while-loop


【解决方案1】:

这个问题已经得到解答 - 该语言具有更自然的结构来表达您想要的内容 - 您应该使用它。例如,我当然可以这样写:

for (bool b = condition(); b; b = !b) {
    /* more code */
}

或:

while (condition()) {
    /* more code */
    break;
}

而不是更传统的:

if (condition()) {
    /* more code */
}

但是为什么呢? C(和所有语言)都有习语,其中大多数在表达性和意义期望方面具有合理的意义。当您使用成语时,您会弄乱必须阅读您的代码的人的感受。

【讨论】:

    【解决方案2】:

    有什么理由使用后者 而不是前者?

    1. 误导您的同事,让您知道这两种形式是等效的。
    2. 一种愚蠢的做法,通过使您的代码尽可能混乱以确保“工作安全”,这样就没有人愿意更改它。
    3. 键盘上的“w”键坏了。
    4. 它最初是一个带有初始化程序和递增条件的 for 循环,当逻辑发生变化时,开发人员忙于更改它。

    【讨论】:

      【解决方案3】:

      我曾经写过一些非常神秘的 C/C++ 代码。回想起来,我可能会在 while 循环中这样做:

      ifstream f("file.txt");
      char c;
      for(f.get(c); !f.eof(); f.get(c)) {
        // ...
      }
      

      我想我的观点是 for 循环通常更短但可读性较差,如果它们不是在传统意义上的循环范围内使用的话。

      【讨论】:

        【解决方案4】:

        您可能希望使用 do-while 循环而不是 for 循环,以便在检查和满足(或不满足)条件之前至少处理一次代码。

        【讨论】:

          【解决方案5】:

          一些编译器警告常量循环条件:

          while (true) { /* ... */ } /* Warning! */
          for (;;) { /* ... */ } /* No warning */
          

          在无限循环的特定情况下,出于这个原因,我可能会选择 for 循环而不是 while 循环。但如果条件不为空,我真的看不到任何好处。我对为什么它出现在上述项目中的猜测是代码以某种方式通过维护而演变,但最初是以更传统的方式编写的。

          【讨论】:

            【解决方案6】:

            我认为“while”和“for”循环适用于不同的习语。使用“while”的成语是“做某事,而某些条件为真”。 “for”的成语是“迭代一定范围的元素”...

            每当我阅读代码时,我都会期待这些习语(而且我认为我并不孤单)。当我看到“for”时,我明白有人正在迭代某个范围,我不会详细说明。当我看到用于另一个习语的 for 循环(不是我期望的那个)时,我感到困惑,不得不详细说明。

            无论如何,这是非常主观的......

            【讨论】:

              【解决方案7】:

              可以编译

              for(INIT; CONDITION; UPDATE)
              {
                BODY
              }
              

              进入

              {
                INIT
                while(CONDITION)
                {
                  BODY
                  UPDATE
                }
              }
              

              更新:看似多余的额外范围是将任何变量定义限制在 INIT 中,即来自for(int i = 0; ...)。谢谢!

              这基本上只是对表达式的重新排序。因此,出于性能原因,没有理由更喜欢其中一个。如果可能的话,我会推荐while(),因为它更简单。如果一个更简单的结构表达了您想要做的事情,我认为这是可以使用的。

              【讨论】:

              • 请记住,continue 语句在后一种情况下具有不同的语义。
              • 不仅有可能,而且在标准中也是这样定义的,请在此处查看我对这个问题的副本的回答:stackoverflow.com/questions/885908/…
              【解决方案8】:

              在 C-ish 语言中,for (;cond;) 循环和 while 循环之间确实没有区别。一般来说,我在 C-ish 语言中所做的就是开始将循环编写为“for”,如果我以这种形式结束,则将其更改为“while”。不过这有点少见,因为您总是在 something 中进行迭代,而 C 允许您在最后一个区域放置您想要的任何代码。

              如果 C 有 real(预计算迭代)for 循环,情况会有所不同。

              【讨论】:

                【解决方案9】:

                据我所知,没有好的理由。您使用不会增加任何内容的 for 循环故意误导人们。

                更新:

                根据 OP 对该问题的评论,我可以推测您如何在实际代码中看到这样的构造。我以前见过(并使用过)这个:

                lots::of::namespaces::container::iterator iter = foo.begin();
                for (; iter != foo.end(); ++iter)
                {
                    // do stuff
                }
                

                但这就是我将事情排除在 for 循环之外的情况。也许您的项目曾经有一个看起来像这样的循环。如果您在循环中间添加删除容器元素的代码,您可能必须仔细控制iter 的递增方式。这可能会导致代码如下所示:

                for (; iter != foo.end(); )
                {
                    // do stuff
                
                    if (condition)
                    {
                        iter = foo.erase(iter);
                    }
                    else
                    {
                        ++iter;
                    }
                }
                

                但是,这不是不花五秒钟时间将其更改为 while 循环的借口。

                【讨论】:

                  【解决方案10】:

                  没有。没有。没有。

                  即使存在细微的性能差异,您也必须是最终阶段的绝地性能调谐器才能让它足够重要。

                  【讨论】:

                  • 即使有任何性能差异,使用后者仍然只是解决编译器错误(未能优化 while 循环)。
                  • 应该是 Sith 性能调谐器。因为所有像这样的代码级优化都是邪恶的。
                  • @Martin:我想,但我已经归结为我已经从应用程序中调整了日光的情况,直到生成的汇编代码中的微小变化实际上产生了影响,但那是就像榨出最后​​一滴“萝卜的血”。
                  【解决方案11】:

                  我可以看到 2 个原因,我都不会考虑:

                  • 只有 1 个循环构造,但 Kristo 的反对意见成立
                  • 写“for (; EVER;)”,但如果真的需要,更喜欢 LOOP_FOREVER 宏。

                  【讨论】:

                  • for (; EVER;) == while(true) :)
                  • @suszterpatt 它正在阅读“永远”。 @DevSolar:BOOST_FOREACH 呢?
                  【解决方案12】:

                  暂时不考虑可读性,不同循环之间通常没有性能差异。至少没有显着差异。

                  对于桌面应用程序,您可以根据可读性标准进行选择。请参阅其他帖子 - 例如看着 for 循环有人认为增量器是在循环中声明的。

                  这似乎适用于 Web 应用程序,例如客户端脚本可能会有所不同。

                  查看本站:http://www.websiteoptimization.com/speed/10/10-2.html

                  运行您自己的实验并遵循结果,否则请遵守可读性规则。

                  【讨论】:

                  • @sharptooth:在你进行这些实验时,我可以拿着你的钱包吗?
                  【解决方案13】:

                  编译两者并检查生成的反汇编,如果它们相同(它们可能是)。选择你认为最易读的一个。

                  【讨论】:

                    【解决方案14】:

                    在汇编级别上可能存在与编译器相关的微小差异,但理想情况下两者的行为应该完全相同,并且前者更具可读性。所以不,除了不墨守成规之外,没有理由使用后一个版本。

                    【讨论】:

                      【解决方案15】:

                      在这种情况下,我个人更喜欢第一个循环,因为它更容易编写和阅读。

                      但如果我有一个循环需要一些 post 语句,我会像这样使用 for 循环:

                      for (; i < 10; i += 2)
                      

                      【讨论】:

                        【解决方案16】:

                        据我所知,编译器将这两个语句优化为相同的汇编代码。所以不,没有理由这样做 - 只是个人喜好。

                        【讨论】:

                          【解决方案17】:

                          如果你想在有限的时间内做某事,那么“for”让你指定约束,而不会将其与循环内的逻辑混为一谈。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2013-11-18
                            • 2013-02-05
                            • 1970-01-01
                            • 2011-05-06
                            • 1970-01-01
                            • 2021-12-21
                            • 1970-01-01
                            • 2012-09-04
                            相关资源
                            最近更新 更多