使用for_each和range-for有什么好处?

4

我知道历史上使用标准算法,如for_each而不是for循环更易读。但我认为在c++11中,普通的for循环比众多标准算法及其对应的回调函数更简洁。

我这样想错了吗?许多标准算法已经过时了吗?这些方法提供了哪些不同的好处?


1
当并行STL成为标准时,for_each将可以并行化。库构造有时比仅有语言特性更允许抽象。因此,我认为在迁移代码时,for_each可能会更好。 - Germán Diago
@GermánDiago 标准中是否有任何内容防止范围 for 循环的并行化?我期望标准要求“仿佛常规 for 循环”,但保留实现细节(包括并行化)的开放性。 - stefan
1
@GermánDiago 我现在明白你的观点了,谢谢你的澄清。 - stefan
2
你可以使用 break 来中断一个 for 循环,但是你不能使用 break 来中断一个 for_each 循环,所以它们并不完全等价。我会尽可能使用 for_each - sbabbi
为什么您的标题指定了for_each,但正文谈论了一些神秘的“具有相应回调函数的众多标准算法”和“许多标准算法”?除了for_each()之外,还有哪些特定的<algorithm>与本文相关?如何将它们替换为范围-for循环? - underscore_d
显示剩余2条评论
3个回答

4

请根据自己的判断力使用合适的方法。

C++11引入了lambda表达式和更好的bind表达式,使得许多算法在C++中的使用变得更加简单明了,你可以相对简洁地指定函数对象。但是,基于范围的for循环也是一个完全合法的选择。

如果你只需要在循环体中执行一两个语句,那么尽管使用基于范围的循环。如果你需要在一组对象上调用成员函数,则可以考虑使用for_eachmem_fn。如果绑定表达式看起来足够清晰,则可以使用它。但无论你做什么,如果发现自己将过多的逻辑集中到一个地方,请考虑重构代码,并为较小的工作组件命名以提高可读性。

C++提供了许多工具,一个工具的存在并不意味着另一个工具无用。像C++这样的强大编程语言面向有经验的用户,经验会帮助你选择正确的工具来完成正确的工作。


3

就可读性而言,使用基于范围的for循环现在可能比使用std::for_each稍微好一些。但这并不意味着for_each已经过时。

请看下面的代码:

auto myVals = getManyValsInAContainer();

for (auto& val : myVals)
{
    doStuff(val);
}

它做的事情与这段难以阅读的代码相同:

auto myVals = getManyValsInAContainer();

for (auto it = myVals.begin(), end = myVals.end(); it != end; ++it)
{
    doStuff(*it);
}

现在,假设您的容器是一个std::deque,这意味着您的值在大块连续的内存中,有一些指针来跟踪这些块的位置。对于知道实现方式的人来说,遍历该容器的所有元素很容易:只需要双重循环即可遍历每个块中的每个元素。
但是对于基于范围的for循环来说呢?它依赖于operator++()从一个元素移动到下一个元素。每次这样做时,operator++()必须检查下一个元素是否在同一个块中,或者是否需要转到下一个块。这些调用是完全独立的,因此没有办法使事情更有效率。
(注意:不要试图手动进行操作:您需要访问容器的私有部分,即使您拥有它,您所想出的任何方法也仅适用于STL的某些实现,而不是其他实现)
那么,当涉及到std::for_each时是否有任何不同呢?首先,它是一个函数模板,因此它可以专门化。它也是STL的一部分,这意味着实现它的人员非常了解std::deque(或者您正在使用的其他STL容器)的实现方式,并且他们可以使std::for_each成为容器类的友元(或者做任何其他需要做的事情),以便高效地进行操作,而不是依赖于多个对operator++()的调用。
因此,这就是您的答案:std::for_each并不过时。可读性只是它的一项优点,但在迭代STL容器时,它仍然比任何for循环更有效率。

1
这将是一个相当主观的话题,但就其价值而言,我同意你的观点。我认为使用语言结构胜过库结构要好得多,特别是当语言结构简洁易读时。(虽然在c++11之前,对于for_each的可读性肯定有争议)

我倾向于同意。另一方面,有了C++11的lambda表达式,现在至少不必再写很多函数对象类了。 - Erik Alapää
1
@ErikAlapää 我讨厌C++的lambda表达式。Boost.Phoenix的lambda表达式看起来更好,对于小函数而言语法噪音要少得多。将[](int a, int b){return a+b;}_1+_2进行比较。 - KitsuneYMG
有些匿名函数总比没有好,但我必须同意@KitsuneYMG的观点。 - sircodesalot

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