STL: 用纯函数做判断式

一、必要的概念

●     判断式是返回bool(或者其他可以隐式转化为bool的东西)。判断式在STL中广泛使用。标准关联容器的比较函数是判断式,判断式函数常常作为参数传递给算法,比如find_if和多种排序算法。


●     纯函数是返回值只依赖于参数的函数。如果f是一个纯函数,x和y是对象,f(x, y)的返回值仅当x或y的值改变的时候才会改变。 

●     一个判断式类是一个仿函数类,它的operator()函数是一个判断式,也就是,它的operator()返回true或false(或其他可以隐式转换到true或false的东西)。正如你可以预料到的,任何STL想要一个判断式的地方,它都会接受一个真的判断式或一个判断式类对象。


二、举例:不用纯函数判断式

考虑下面(坏的实现)的判断式类。不管传递的是什么实参,它严格地只返回一次true:第三次被调用的时候。其他时候它返回假。


class BadPredicate:  public unary_function<Widget, bool> {  
public:

// 把timesCalled初始化为0
        BadPredicate(): timesCalled(0) {}               
        bool operator()(const Widget&){
                return ++timesCalled == 3;
        }


private:
        size_t timesCalled;
};


假设我们用这个类来从一个vector<Widget>中除去第三个Widget:

// 建立vector,然后
vector<Widget> vw;                              
// 放一些Widgets进去

...

// 去掉第三个Widget;
vw.erase(remove_if(vw.begin(), vw.end(), BadPredicate()),  vw.end());
这段代码看起来很合理,但对于很多STL实现,它不仅会从vw中除去第三个元素,它也会除去第六个!


要知道这是怎么发生的,就该看看remove_if一般是怎么实现的。记住remove_if不是一定要这么实现:


template <typename FwdIterator, typename Predicate>
FwdIterator remove_if(FwdIterator begin, FwdIterator end, Predicate p){
        begin = find_if(begin, end, p);
        if (begin == end) return begin;
        else {
                FwdIterator next = begin;
                return remove_copy_if(++next, end. begin, p);
        }
}


这段代码的细节不重要,但注意判断式p先传给find_if,后传给remove_copy_if。当然,在两种情况中,p是传值——是拷贝——到那些算法中的


最初调用remove_if(用户代码中要从vw中除去第三个元素的那次调用)建立一个匿名BadPredicate对象,它把内部的timesCalled成员清零。这个对象(在remove_if内部叫做p)然后被拷贝到find_if,所以find_if也接收了一个timesCalled等于0的BadPredicate对象。find_if“调用”那个对象直到它返回true,所以调用了三次,find_if然后返回控制权到remove_if。remove_if继续运行后面的调用remove_copy_if,传p的另一个拷贝作为一个判断式。但p的timesCalled成员仍然是0!find_if没有调用p,它调用的只是p的拷贝。结果,第三次remove_copy_if调用它的判断式,它也将会返回true。这就是为什么remove_if最终会从vw中删除两个Widgets而不是一个。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值