C++ 人们应该更喜欢STL算法而不是手动循环吗?

C++ 人们应该更喜欢STL算法而不是手动循环吗?,c++,algorithm,stl,C++,Algorithm,Stl,我在问答中看到的迭代器上的“for”循环似乎比我对_each()、transform()等的循环要多。斯科特·梅耶斯(Scott Meyers)提出了这一建议,至少在2001年是这样。当然,使用它们通常意味着将循环体移动到函数或函数对象中。有些人可能会觉得这是一个不可接受的复杂问题,而另一些人可能会觉得它更好地解决了问题 所以。。。STL算法是否应优先于手动循环?这取决于: 是否需要高性能 循环的可读性 算法是否复杂 如果循环不是瓶颈,算法简单(如FoY-ALL),那么对于当前的C++标准,

我在问答中看到的迭代器上的“for”循环似乎比我对_each()、transform()等的循环要多。斯科特·梅耶斯(Scott Meyers)提出了这一建议,至少在2001年是这样。当然,使用它们通常意味着将循环体移动到函数或函数对象中。有些人可能会觉得这是一个不可接受的复杂问题,而另一些人可能会觉得它更好地解决了问题

所以。。。STL算法是否应优先于手动循环?

这取决于:

  • 是否需要高性能
  • 循环的可读性
  • 算法是否复杂

如果循环不是瓶颈,算法简单(如FoY-ALL),那么对于当前的C++标准,我更喜欢手工滚动循环来进行可读性。(逻辑的局部性是关键。)


然而,现在一些主要的编译器支持C++0x/C++11,我建议使用STL算法,因为它们现在允许lambda表达式,从而允许逻辑的局部性。

我不会对其使用硬性规则。有很多因素需要考虑,就像你经常在代码中执行某个操作一样,只是一个循环或一个“实际”的算法,这个算法取决于你必须向你的函数发送的很多上下文吗? 例如,我不会把

for (int i = 0; i < some_vector.size(); i++)
    if (some_vector[i] == NULL) some_other_vector[i]++;
for(int i=0;i
因为这将导致更多的代码百分比,我将不得不处理如何让算法知道一些其他向量


还有很多其他例子表明,使用STL算法很有意义,但您需要根据具体情况做出决定。

这取决于,如果算法不采用函子,则始终使用std算法版本。你写起来既简单又清晰


对于采用函子的算法,通常为否,直到可以使用C++0x lambdas。如果函子很小,算法很复杂(大多数不是),那么最好还是使用std算法。

这确实是Scott Meyers弄错的一件事

如果有一个实际的算法与您需要做的匹配,那么当然要使用该算法

但是,如果您只需要循环一个集合并对每个项执行某些操作,那么只需执行普通的循环,而不是尝试将代码分离到不同的函子中,这只会将代码分割成位,而没有任何实际收益

还有一些其他选项,如boost::bind或boost::lambda,但这些都是非常复杂的模板元编程,它们在调试和单步执行代码时效果不太好,因此通常应该避免使用它们


正如其他人提到的,当lambda表达式成为一等公民时,这一切都会改变。

我认为一个重要因素是开发者的舒适度

使用transform或for_是正确的做法,这可能是对的,但它没有任何效率,手写循环也没有本质上的危险。如果开发人员编写一个简单的循环需要半个小时,而获得transform或for_的语法并将提供的代码移动到函数或函数对象中则需要半天。然后其他开发人员需要知道发生了什么

对于一个新的开发人员来说,学习使用transform和for_each可能比手工制作的循环更好,因为他能够始终如一地使用它们而不会出错。对于我们其他人来说,编写循环是他们的第二天性,最好还是坚持我们所知道的,在业余时间更熟悉算法


这样说吧——如果我告诉我的老板我花了一整天的时间将手工制作的循环转换为for_和transform调用,我怀疑他是否会很高兴。

我认为STL算法接口是次优的,应该避免使用,因为直接使用STL工具包(用于算法)可能会在性能上获得很小的提升,但是,当您学习如何使用这些工具时,肯定会花费可读性、可维护性,甚至一点可写性

向量上循环的标准效率有多高:

int weighted_sum = 0;
for (int i = 0; i < a_vector.size(); ++i) {
  weighted_sum += (i + 1) * a_vector[i];  // Just writing something a little nontrivial.
}
int加权总和=0;
对于(int i=0;i
而不是在每个构造中使用for_,或者尝试将其放入一个累积调用中

您可能会认为迭代过程效率较低,但for uueach也会在每个步骤中引入函数调用(这可以通过尝试内联函数来缓解,但请记住,“内联”只是对编译器的一个建议,它可能会忽略它)

无论如何,差别很小。根据我的经验,您编写的90%以上的代码都不是性能关键型的,而是编码器时间关键型的。通过保持STL循环完全在线,它是非常可读的。对于您自己或未来的维护人员来说,没有太多的间接失误。如果它在你的风格指南中,那么你为你的程序员节省了一些学习时间(承认这一点,第一次学习正确使用STL需要一些时间)。最后一点就是我所说的可写性成本


当然也有一些特殊情况——例如,您可能实际上希望将每个函数分离出来,以便在其他几个地方重复使用。或者,它可能是为数不多的高性能关键部分之一。但是这些都是特殊情况——例外而不是规则。

for
循环的
是必需的,算法是声明性的。当您编写
std::max_element
时,很明显您需要什么,当您使用循环来实现同样的功能时,不一定如此

算法也可能有轻微的性能
#include <string>
#include <iostream>
#include <boost/foreach.hpp>

int main()
{
    std::string hello( "Hello, world!" );

    BOOST_FOREACH( char ch, hello )
    {
        std::cout << ch;
    }

    return 0;
}
for (vector<Child>::iterator iter = children.begin();
    iter != children.end();
    ++iter)
{
    iter->setFooCount(n);
}
for_each(children.begin(), children.end(), SetFooCount(n));
class SetFooCount
{
public:
    SetFooCount(int n) : fooCount(n) {}

    void operator () (Child& child)
    {
        child.setFooCount(fooCount);
    }

private:
    int fooCount;
};