• 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++标准程序库的仿函数一节)。

  • 相关阅读:
    邻居子系统 之 更新neigh_update
    邻居子系统 之 邻居项查找neigh_lookup、___neigh_lookup_noref
    遍历集合的方法总结
    Java集合中List,Set以及Map等集合体系
    八大数据结构分类
    servlet和jsp的区别
    Web前端和Web后端的区分
    (转)为什么JavaWeb放弃jsp,去做前后端分离
    面向对象的三大基本特征和五大基本原则
    (转)2019年给Java编程初学者的建议(附学习大纲)
  • 原文地址:https://www.cnblogs.com/acros/p/3218877.html
Copyright © 2020-2023  润新知