【问题标题】:Proper use of C++ 'for each' options正确使用 C++ 'for each' 选项
【发布时间】:2023-04-01 04:18:02
【问题描述】:

Thesequestions 让我对 Boost 和 Qt 的 for each 宏的用途感到好奇。

我使用过 Qt 并发现该宏始终可以很好地满足我的需求,但从未广泛测试过它的性能。我之前没有使用过 Boost 的产品。

我想知道什么时候是使用 Qt 和 Boost 提供的替代方案而不是 std::for_each 的好时机?

注意:措辞已从the original 更改为使问题更加客观。

【问题讨论】:

  • std::for_each 至少从 C++98 开始就存在了,所以如果你找到一个支持它的编译器,我会很惊讶。话虽如此,您所要求的本质上是主观的,因此对于 SO 来说不是一个好问题。
  • 如何在不给出个人意见的情况下提供赞成或反对意见,根据定义,这是主观的?
  • 您有文档的链接。该文档描述了这些功能的作用。你不能通过比较描述来得出差异吗?
  • 在某些情况下,您可能也不必为停车付费,所以不,我们不同意。底线是Stack Overflow is not a List for All Thingsnor is it a Recommendation Enginenor is it your personal research assistant——这个问题根本不适合 IMO。
  • @ildjarn:我也怀疑 PSE 是不是合适的地方——它们不是我们的垃圾场。我认为 SE 上没有任何地方不会解决这个问题。

标签: c++ qt boost foreach std


【解决方案1】:

std::for_each 的用途和功能与宏 BOOST_FOREACHQ_FOREACH 的用途和功能非常不同。

std::for_each 首先是一个函数调用。它是一种算法。您调用它,提供一对迭代器。在迭代器范围的每个成员上,它将使用从相关迭代器中获取的值调用给定函数。

std::for_each 的目的,从概念上讲,确实是为了匹配已经存在的更具体的算法。对于 countcopy 等算法,有一个简单地为每个元素执行任意代码的算法是有意义的。

BOOST_FOREACHQ_FOREACH 是等效的结构(我将它们统称为FOREACH),但行为不同于std::for_each

FOREACH 首先是一个 for 循环。现在,这听起来可能没什么不同,但想想看。您不能从std::for_each 中调用continuebreakcontinue 可以很容易地用return 模拟(尽管这也意味着您不能从发出std::for_each 调用的函数返回)。但是如果你想停下来,就没有办法逃离std::for_each 循环。同样,您不能将goto 退出for_each 循环。在这两种情况下,你能做的最好的事情就是抛出一个异常,那就是使用异常来进行流控制(即:不是一个好主意)。

当你使用std::for_each时,你必须提供一些可调用的函数。这可以是函数指针或函数对象。因此,您的代码有些去本地化。如果您在每次迭代中所做的是一个复杂的多行函数,这很好。但是如果每次迭代的逻辑都非常简单,那么代码的可读性就会下降一点。

FOREACH 执行本地代码块。所以代码就在那里;您无需跟踪函数即可查看每次迭代中发生的情况。

此外,调用函数意味着必须编写该函数。如果您需要跟踪状态,您现在需要一个函子,这需要编写更多代码。

C++11 使 std::for_each much 对 lambda 函数更具吸引力。这消除了代码局部性问题:源代码就在那里。而且由于 lambdas 可以捕获内容,它几乎可以像常规的 for 循环一样工作。好吧,除了没有break 功能,但这通常是可以避免的。

当然,C++11 还通过基于范围的for 循环使其有效地过时(以及FOREACH)。但由于与 C++11 的一致性级别不同,因此在某些环境中您有 lambda 但不是基于范围的for

应该使用什么由您决定。 FOREACH 很好,如果您已经在使用 Boost 和/或 Qt,请随意。但我不会突然开始为FOREACH 使用这些。就个人而言,我不会使用std::for_each,除非您还使用 lambdas 或其他东西,因为代码位置问题。只需使用for 循环即可。

【讨论】:

  • 感谢 Nicol,您对用例的说明很到位。
【解决方案2】:

std::for_each 是 C++ 标准的一部分,自 1998 年以来(至少)一直如此。因此,任何(不是那么)现代 C++ 都是不兼容,因此如果它不提供 for_each 就会被破坏。我每天使用的所有编译器都支持它。

您提到的两个库都存在于 C++ 语言本身之外。 for_each 是唯一一个保证出现在符合标准的编译器中。

至于利弊,我留给你决定。如果可以选择,我会选择标准保证的东西,而不是不保证的东西。

【讨论】:

  • for_each 的速度比正常的循环机制快吗?
  • 标准说它在 O(n) 时间内运行。在我见过的每一个实现中,它只是一个 for 循环,至少与一般意义上的任何你能写的东西一样快。
  • 话虽如此,执行速度既不是使用for_each的典型理由,也不是不使用的理由。
  • 我的问题不是时间复杂度,任何循环(for、for_each、while)都可以在 O(n) 中工作。我的问题是使用 for_each 是否比使用标准 for 有开销。谢谢。
  • 这是一个inline 函数调用。其他一切都是实现定义的,但正如我所说,我从未见过比手写代码更糟糕的实现。如果这是一个主要问题,我建议您查看 您的 实现。
【解决方案3】:

std::for_each 需要 functorlambdafunction-pointer 来执行。如果您在代码中的多个位置循环使用相同的方法,使用它可以避免大量样板文件。

 void hello(int i){
      printf("World %d \n",i);
 }

 std::vector<int> vals;
 vals.push_back(1);
 vals.push_back(2);
 std::for_each(vals.begin(),vals.end(),hello);

BOOST_FOREACH 和 Q_FOREACH 用于隐藏 c++ 迭代器的样板文件,它们替换了正常的 for 语句并在循环体上循环。

  for(vector<int>::iterator iter = vals.begin();iter != vals.end();++iter)
  {
      hello(*iter);
  }

  Q_FOREACH(int val, vals){
      hello(val);
  }

用法:你认为哪个最易读,并避免不必要的代码重复。

性能:每一个都是宏或模板函数,并且对编译器完全可见,差异应该只存在于调试版本中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2020-06-16
    相关资源
    最近更新 更多