STL中仿函数的简要回顾

前两天做项目时用STL的排序时犯了一个低级错误,错误产生的原因是这样的: 

原先编码有一vector存放一组类,其中类简化定义如下:

  class UserInfo
  {
   public:     
int   m_iIndex;
int m_iInfo;   };   vector<UserInfo*>  UserInfoList;

 这个vector需要排序处理(此处不考虑排序性能相关选择),于是调用STL的sort()排序。STL默认调用“<”进行比较,因此要给UserInfo类添加操作符"<"的重载:

  class UserInfo
  {
  public:     
int   m_iIndex;     int m_iInfo;      bool operator<(const UserInfo& _rhs) const     {       if(m_iIndex < _rhs.m_iIndex)         return true;       else         return false;     }   };

写好操作符重载就可以直接进行排序了?

  sort(UserInfoList.begin(),UserInfoList.end());    //Warning:此时以指针地址排序!

在运行时立马发现犯了一个低级错误,上面的sort语句是根据vector中的内容,即指针地址进行排序的!

为了让sort()以我们期望的方式排序,应该写成以下这样子

sort(UserInfoList.begin(),UserInfoList.end(), SortUserInfoMethod() );

  这第三个参数:仿函数--SortUserInfoMethod()就是今天的主角了。

  仿函数本质是一个类,但是有一个重载了”()“操作符的成员函数,SortUserInfoMethod(),此处作为sort排序的准则使用(sort调用了SortUserInfoMethod的操作符“()”这个函数)。

SortUserInfoMethod仿函数的定义:

class SortUserInfoMethod
{
public:
    bool operator()(const UserInfo* _pInfo1,const UserInfo* _pInfo2    )const
    {
            return _pInfo1->index < _pInfo2->index;
    }
};

仿函数有一个好处是能在内部记录状态。如上的例子中,如果想查看sort排序时每次的动作,只需改写SortUserInfoMethod如下(注意此处例子只为说明内部状态的改变,开发编写时不推荐在仿函数判断式内改变自身状态,operator()应为const):

class SortUserInfoMethod
{
public:
        SortUserInfoMethod():iCount(0){}

    bool operator()(const UserInfo* _pInfo1,const UserInfo* _pInfo2    )
    {
                        cout<<iCount++<<endl;
            return _pInfo1->index < _pInfo2->index;
    }

private:
   int iCount;     
};

此时每次排序比较,都会让iCount自增一次并打印。

值得注意的是,sort函数内部会为SortUserInfoMethod创建一个该类的实例,这个状态变化只在sort函数内部进行!换言之,sort()再调用一次SortUserInfoMethod(),iCount仍然是从初始化值开始计数的!

如果要保存仿函数内部状态,某些情况下也可以实现,包括template参数改成传址,for_each()会返回其仿函数等等,不过这种方法似乎过于技巧化····(实例见Nicolai的C++标准程序库的仿函数一节)。

原文地址:https://www.cnblogs.com/acros/p/3218877.html