使用 for_each 与范围有什么好处

What are the benefits of using for_each vs. range-for?

本文关键字:什么 范围 for each 使用      更新时间:2023-10-16

我知道从历史上看,最好使用标准算法(如for_each)而不是for循环,因为它们更具可读性。但我只是觉得使用 c++11 的常规 for 循环比具有相应回调函子的众多标准算法要简洁得多。

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

使用你的判断。

由于 lambda 和更好的绑定表达式,许多算法在 C++11 中变得更容易使用,这允许您以相对简洁的方式指定函子。但是,基于范围的for循环也是一个完全合法的选择。

如果您只需要循环体中的一个或两个语句,那么一定要使用基于范围的循环。如果需要在对象集合上调用成员函数,可以使用 for_eachmem_fn 。如果绑定表达式看起来足够清晰,请使用它。但无论你做什么,如果你发现自己在一个地方塞进了太多的逻辑,请考虑重构并为较小的工作组件提供可读的名称。

C++为您提供了许多工具,一种工具的存在并不意味着另一种工具毫无用处。大型工具带,就像C++一样,针对有经验的用户,经验可以让您为正确的工作选择正确的工具。

在可读性方面,使用基于范围的 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 ,这意味着您的值位于连续内存的大块中,并带有一些指针来跟踪这些块的位置。对于了解实现的人来说,遍历该容器的所有元素很容易:它只需要一个双循环来遍历每个块的每个元素。

但是基于范围的呢?它依赖于operator++()从一个元素移动到下一个元素。每次这样做时,operator++()都必须检查下一个元素是否在同一个块中,或者是否需要继续下一个块。这些调用彼此完全独立,因此无法提高效率。

(注意:不要尝试手动做事:为此,您需要访问容器的私有部分,即使您拥有它,无论您想出什么都仅适用于 STL 的某些实现,而不适用于其他实现)

那么在std::for_each方面有什么

不同吗?嗯,一方面它是一个函数模板,所以它可以是专门的。它也是 STL 的一部分,这意味着实现它的人确切地知道std::deque(或你正在使用的任何其他 STL 容器)是如何实现的,并且他们可以std::for_each成为容器类的朋友(或做他们需要做的任何其他事情)来有效地做事,而不是依赖多次调用来operator++()

所以,你的答案是:std::for_each并没有过时。可读性只是它要做的事情之一,但在迭代 STL 容器时,它仍然比任何 for 循环更有效。

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