Kev*_*vin 19
这取决于:
如果循环不是瓶颈,并且算法很简单(如for_each),那么对于当前的C++标准,我更喜欢手动循环以提高可读性.(逻辑的局部性是关键.)
但是,现在C++ 0x/C++ 11受到一些主要编译器的支持,我会说使用STL算法,因为它们现在允许使用lambda表达式 - 因此也就是逻辑的局部性.
我将在这里反对,并提倡使用STL算法和仿函数使代码更易于理解和维护,但你必须正确行事.你必须更加注意可读性和清晰度.特别是,你必须得到正确的命名.但是当你这样做时,你最终会得到更清晰,更清晰的代码,并且范式转变为更强大的编码技术.
我们来举个例子吧.这里我们有一组孩子,我们想把他们的"Foo Count"设置为某个值.标准的for循环迭代器方法是:
for (vector<Child>::iterator iter = children.begin();
iter != children.end();
++iter)
{
iter->setFooCount(n);
}
Run Code Online (Sandbox Code Playgroud)
哪个,是的,它非常清楚,而且绝对不错的代码.只需稍微看一下就可以搞清楚.但是看看我们可以用适当的仿函数做些什么:
for_each(children.begin(), children.end(), SetFooCount(n));
Run Code Online (Sandbox Code Playgroud)
哇,这正是我们所需要的.你不必弄清楚; 你立即知道它正在设定每个孩子的"Foo计数".(如果我们不需要.begin()/ .end()废话,那就更清楚了,但你不能拥有一切,而且在制作STL时他们没有咨询我.)
当然,你确实需要定义这个神奇的仿函数SetFooCount,但它的定义很漂亮:
class SetFooCount
{
public:
SetFooCount(int n) : fooCount(n) {}
void operator () (Child& child)
{
child.setFooCount(fooCount);
}
private:
int fooCount;
};
Run Code Online (Sandbox Code Playgroud)
总的来说,它是更多的代码,您必须查看另一个地方才能确切了解SetFooCount正在做什么.但是因为我们很好地命名,99%的时间我们不必查看代码SetFooCount.我们假设它按照它所说的做,我们只需要查看该for_each行.
我真正喜欢的是使用算法会导致范式转换.您不必将列表视为对象集合,而是对列表的每个元素执行操作,而是将列表视为第一类实体,并直接在列表本身上操作.for循环遍历列表,在每个元素上调用成员函数来设置Foo Count.相反,我正在做一个命令,它设置列表中每个元素的Foo Count.它很微妙,但当你看到森林而不是树木时,你会获得更多的力量.
因此,通过一些思考和仔细的命名,我们可以使用STL算法来制作更清晰,更清晰的代码,并开始在更细粒度的层次上思考.
该std::foreach是什么样的代码,让我骂了STL,年前.
我不能说它是否更好,但我更喜欢在循环前导下使用我的循环代码.对我来说,这是一个强烈的要求.并且std::foreach构造不允许我(奇怪的是,就我而言,Java或C#的foreach版本很酷......所以我猜它确认了对我来说循环体的局部性是非常重要的).
因此,只有当只有一个可读/可理解的算法可用时,我才会使用foreach.如果没有,不,我不会.但这是一个品味问题,我想,因为我应该更加努力地去理解并学会解析所有这些......
请注意,加速的人显然感觉有点相同,因为他们写了BOOST_FOREACH:
#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;
}
Run Code Online (Sandbox Code Playgroud)
请参阅:http://www.boost.org/doc/libs/1_35_0/doc/html/foreach.html
小智 6
这真是Scott Meyers出错的一件事.
如果存在与您需要做的匹配的实际算法,那么当然使用该算法.
但是如果你需要做的就是遍历一个集合并对每个项目做一些事情,那么只需执行正常的循环而不是尝试将代码分离到另一个函子中,这样就最终将代码切割成比特而没有任何实际的好处.
还有一些其他的选项,比如boost :: bind或boost :: lambda,但那些是非常复杂的模板元编程的东西,它们在调试和单步执行代码时效果不佳所以通常应该避免使用它们.
正如其他人所提到的,当lambda表达式成为一等公民时,这一切都将改变.
循环for是命令性的,算法是声明性的。当你写 时std::max_element,它\xe2\x80\x99s 显然是你需要的,当你使用循环来实现同样的目的时,它\xe2\x80\x99s 不一定如此。
算法也可能具有轻微的性能优势。例如,当遍历 时std::deque,专门的算法可以避免冗余地检查给定增量是否将指针移动到块边界上。
然而,复杂的函子表达式很快就会导致算法调用变得不可读。如果显式循环更具可读性,请使用它。如果算法调用可以在没有十层绑定表达式的情况下表达,那么无论如何都更喜欢它。在这里,可读性比性能更重要,因为这种优化正是高德纳 (Knuth) 对霍尔的著名评价;一旦你意识到\xe2\x80\x99是一个瓶颈,你\xe2\x80\x99就能够毫无问题地使用另一个结构。
\n| 归档时间: |
|
| 查看次数: |
7679 次 |
| 最近记录: |