Foreach循环和For循环的区别是什么?

4

如果使用for循环和foreach循环都可以完成同样的工作,那么它们之间的真正区别是什么呢?我正在学习C++,但似乎它的数组中没有foreach循环:(


2
使用STL容器而不是数组,你确实有它。请参考http://www.cplusplus.com/reference/algorithm/for_each/。 - Brian Roach
1
@BrianRoach 实际上,你甚至不需要在最新的标准中使用STL容器。你可以在std::for_each函数中使用std::begin()std::end() - Michael Price
Qt(一种流行的跨平台C++工具包)提供了一个foreach结构。 - Nathan Osman
@MichaelPrice - 是啊...我对以C++11回答C++问题还是以Java 7回答Java问题有点犹豫。我认为提供它作为额外的选择是负责任的做法。 - Brian Roach
@BrianRoach 鉴于这更具有元信息性,我更倾向于废弃C++11标签,转而添加一个保留给特定版本问题的C++ 98/03标签。回答同理。唯恐那些编译器无法实现完整的标准。 - Michael Price
6个回答

6

C++中没有“foreach”语言结构,至少不是字面意义上的。然而,C++11引入了一种与foreach循环“一样好”的东西。

传统的for循环涉及评估条件和执行重复操作。它是一种非常通用的控制结构。它最流行的用途是迭代容器或数组内容,但这只是你可以使用它的一小部分。

另一方面,“foreach”循环明确设计为迭代容器元素。

例如:

int arr[5] = { 1, 3, 5, 2, 4 };

for (int & n : arr) { n *= 2; } // "for-each" loop, new in C++11

for (size_t i = 0; i != 5; ++i) { arr[i] *= 2; } // "classic" for loop

在第二个for循环中,我们使用传统的`for`循环来递增辅助变量`i`以访问容器`arr`。而第一个基于范围的循环并不暴露迭代的任何细节,只是说“对集合中的每个元素执行这个和那个操作”。
由于传统的`for`循环是一个非常通用的控制结构,因此它也可以以不寻常的方式使用。
std::vector<std::string> all_lines;
for (std::string line; std::cin >> line; all_lines.push_back(line))
{
  std::cout << "On line " << (all_lines.size() + 1) << " you said: " << line << std::endl;
}

您可以轻松地将 for(A; B; C) 重写为 while 循环:

{  // scope!
  A;
  while (true && B)
  {
    {  // more scope!
      /* for loop body */
    }
    C;
  }
}

编辑:我不提到库函数模板 std::for_each 来自 <algorithm>,结合lambda表达式,是迭代任意范围(不仅仅是整个容器)的非常好的和自我描述的方法。它已经存在了很久,但在lambda之前,使用起来很麻烦。


更新:我想到了另一个可能与此相关的事情:“foreach”循环通常假定您不会修改容器。一种常见类型的循环需要传统的for循环来修改容器;例如,在这个典型的erase模式中:

for(Container::const_iterator it = v.begin(); it != v.end() /* not hoisted! */; /* no increment */ )
{
  // do something
  if (suitable_condition)
  {
    v.erase(it++);   // or it = v.erase(it), depending on container type
  }
  else
  {
    ++it;
  }
}

所以实际上我可以互换使用它们,但是可能使用for循环可以做更多的事情? - Howdy_McGee
@Howdy_McGee:是的。我添加了一个不寻常的for示例。标准的for循环实际上只是缩写为“a)初始化一些东西;b)如果某些条件成立,则执行某些操作;c)执行某些操作;d)转到b)”。 - Kerrek SB
1
@Howdy_McGee:这一切都关乎意图的表达。如果你有一个容器,for-each(或在C++中称为ranged-for)循环可以让你表达你想要访问容器元素,仅此而已。请注意,基于范围的循环具有更简单的主体,因为没有暴露不必要的信息。编程就是关于表达心理模型,拥有一个惯用的结构有助于使您的代码更清晰和更易于理解。 - Kerrek SB
我对这个“为什么”问题的答案是为了语法糖……它可以减少大部分相同行为的打字量。如果您可以访问集合对象,通常不需要访问该对象所在的索引。 - dlgrasse
或者用一句话说,“没有人想读别人的 for 循环。” 有了基于范围的循环,这可能会变得稍微不那么痛苦。 - Kerrek SB
显示剩余6条评论

1

foreach 通常有一个参数,for 有3个参数。任何 foreach 可以做的事 for 也可以做。其中一个原因是 foreach 在 C++ 中不存在的部分原因是循环次数不能总是从类型中推断出来。

我相信 boost 库有一种方法可以让 foreach 工作,并且 C++11 有基于范围的 for

int my_array[5] = {1, 2, 3, 4, 5};
for (int &x : my_array) {
    x *= 2;
}

1

C++中有类似于数组的for each循环,即迭代器。两种循环本质上是相同的,唯一的区别在于:普通的for循环需要一个索引,这取决于你访问的数据类型以及是否需要使用索引进行一些计算,同时也可能会增加出错的机会。而foreach循环只保证将执行与数组元素数量相同的次数,不暴露索引(但你可以模拟),所以它们本质上是相同的,但它们的使用方式主要取决于你如何操作数据。


0
"

“For Each”语法用于迭代对象集合,而for循环是在给定范围内执行的循环。C++在其STL中确实有for_each函数,可用于迭代线性对象容器,例如向量。

"

一个 for 循环与“范围”无关。它是用于检查条件并执行语句的。 - Kerrek SB
从技术上讲,您是正确的,但与for_each 相比,range 更合适。我甚至要声明,大多数编写的for循环条件都基于某种范围,并且通常迭代一些类型的索引数据。当您有do和while循环可用时,使用for循环测试布尔“条件”是不合适的。 - Daniel Pereira

0
在其他使用foreach结构的语言中,它们通常是为了方便而不必索引正在循环的集合。也就是说,你可以获得集合中的下一个对象,而不需要访问(或需要)索引本身。如果出于某种原因需要索引,则通常需要使用for循环,尽管在某些语言中,您可以在其“foreach”中访问计数器。

0
作为经验测试,FOR比FOREACH更快。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接