Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1798988
  • 博文数量: 600
  • 博客积分: 10581
  • 博客等级: 上将
  • 技术积分: 6205
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-06 10:13
文章分类
文章存档

2016年(2)

2015年(9)

2014年(8)

2013年(5)

2012年(8)

2011年(36)

2010年(34)

2009年(451)

2008年(47)

分类: C/C++

2009-09-19 12:07:58

了解copy_if的正确实现

STL有很多有趣的地方,其中一个是虽然有11个名字带“copy”的算法:

copy

copy_backward

replace_copy

reverse_copy

replace_copy_if

unique_copy

remove_copy

rotate_copy

remove_copy_if

partial_sort_copy

unintialized_copy

 

但没有一个是copy_if。这意味着你可以replace_copy_if,你可以remove_copy_if,你可以copy_backward或者reverse_copy,但如果你只是简单地想要拷贝一个区间中满足某个判断式(predicate)的元素,你只能自己做。

比如,假设你有一个函数来决定一个Widget是否有缺陷的:

bool isDefective(const Widget& w);

而且你希望把一个vector中所有缺陷的Widget写到cerr。如果存在copy_if,你可以简单地这么做:

vector<Widget> widgets;

...

copy_if(widgets.begin(), widgets.end(),   // 这无法编译:

  ostream_iterator(cerr, "\n"), // STL中并没有copyif

  isDefective);

具有讽刺意味的事,copy_if是最初的惠普STL的一部分,惠普STL形成了STL的基础,而STL现在是标准C++库的一部分。有些怪癖会使历史变得有趣,在从HP STL中为标准筛选出一些大小易于管理的东西时,copy_if成了其中一个在剪接室中被遗弃的东西。

在《The C++ Programming Language[7]Stroustrup强调写copy_if是微不足道的,他是对的,但那不意味着实现正确的琐事很简单。比如,这里有一个合理的看待copy_if,很多人(包括我)曾经知道的实现:

template<typename InputIterator,    // 一个不很正确的

   typename OutputIterator,  // copy_if实现

   typename Predicate>

OutputIterator copy_if(InputIterator begin,

    InputIterator end,

    OutputIterator destBegin, Predicate p)

{

 return remove_copy_if(begin, end, destBegin, not1(p));

}

这个方法是基于这个观点——虽然STL并没有让你说拷贝每个判断式为true的东西,但它的确让你说了拷贝除了判断式不为true以外的每个东西。要实现copy_if,似乎我们需要做的就只是加一个not1在我们希望传给copy_if的判断式前面,然后把这个结果判断式传给remove_copy_if,结果就是上面的代码。

如果上面的理由有效,我们就可以用这种方法写出有缺陷的Widget

copy_if(widgets.begin(), widgets.end(),   // well-intentioned code

  ostream_iterator>(cerr, "\n"), // that will not compile

  isDefective);

你的STL平台将会敌视这段代码,因为它试图对isDefective应用not1(这个应用出现在copy_if内部)。正如条款41试图将清楚的,not1不能直接应用于一个函数指针,函数指针必须先传给ptr_fun。要调用这个copy_if实现,你必须传递的不仅是一个函数对象,而且是一个可适配的函数对象。这够简单了,但是想要成为STL算法用户的人应该不必这样。标准STL算法从来不要求它们的仿函数是可适配的,copy_if也不应该要求。上面的实现是好的,但不够好。

这是copy_if正确的微不足道的实现:

template<typename InputIterator,    // 一个copy_if

   typename OutputIterator,  // 正确实现

   typename Predicate>

OutputIterator copy_if(InputIterator begin,

    InputIterator end,

    OutputIterator destBegin,

    Predicate p) {

 while (begin != end) {

  if (p(*begin))*destBegin++ = *begin;

  ++begin;

 }

 return destBegin;

}

告诉你copy_if多有用,加上新STL程序员趋向于希望无论如何它应该存在的事实,所以好的做法是把copy_if——正确的那个!——放在你局部的STL相关工具库中,而且只要合适就使用。

 

阅读(1066) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~