正确使用C ++'为每个'选项

时间:2012-05-09 21:56:21

标签: c++ qt boost foreach std

These questions让我对每个宏的Boost和Qt 的目的感到好奇。

我已经使用过Qt,并发现宏一直能够满足我的需求,但从未对其性能进行过广泛的测试。我之前没有使用过Boost的产品。

我想知道的是,在std::for_each使用Qt和Boost提供的替代方案的时候会是什么时候?

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

3 个答案:

答案 0 :(得分:5)

std::for_each的目的和功能与宏BOOST_FOREACHQ_FOREACH的目的和功能大不相同。

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

从概念上讲,std::for_each的目的实际上是与已经存在的更具体的算法相匹配。使用countcopy等算法,有一个只为每个元素执行任意代码的方法。

BOOST_FOREACHQ_FOREACH是等效的构造(我将统称为FOREACH),但的行为std::for_each不同。

FOREACH首先是 for循环。现在,这可能听起来不那么不同,但想一想。您无法从continue内拨打breakstd::for_each。使用continue可以轻松模拟return(尽管这也意味着您无法从发出std::for_each调用的函数返回)。但如果你想停下来,就没有办法摆脱std::for_each循环。同样,您不能goto循环for_each。在任何一种情况下你能做的最好就是抛出一个异常,那就是使用流控制的异常(即:不是一个好主意)。

使用std::for_each时,必须提供一些可调用的功能。这可以是函数指针或函数对象。因此,您的代码在某种程度上是非本地化的。如果您在每次迭代中所做的事情是复杂的多线函数,那么这很好。但是,如果每个迭代的逻辑非常简单,那么代码可读性会稍微降低。

FOREACH执行本地代码块。所以代码就在那里;你不必追踪一个函数来看每次迭代发生了什么。

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

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

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

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

std :: for_each需要执行仿函数 lambda 函数指针。使用它,如果在代码中的多个位置循环使用相同的方法,则可以避免大量样板。

 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);
  }

用法:您认为哪种方式最具可读性,避免不必要的代码重复。

性能:这些中的每一个都是宏或模板函数,并且对编译器完全可见,差异应仅存在于调试版本中(如果有的话)。