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