游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4529|回复: 2

重构的力量-对象池

[复制链接]

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
发表于 2011-8-26 12:51:00 | 显示全部楼层 |阅读模式
查看以前写的一个对象池,感觉代码凌乱,今天重构了一下。
#ifndef _TObjectPoolV12_H_
#define _TObjectPoolV12_H_


#include<iostream>

#pragma warning(disable: 4786)//关闭4786错误(STL调试信息过长,超过255字符)
#include<list>
#include<algorithm>

namespace Aura
{
  //TObjectPool1.2
  //对象池模版,池里分配预算定数量的对象,用时从池申请,不用时归还池,采用页链表技术使池理论无上限  
  enum TObjectPool_error
  {
    TObjectPool_error_no,
    TObjectPool_error_memory,      //内存分配错误
    TObjectPool_error_null_pointer,    //无效对象指针
    TObjectPool_error_multiple_return,  //多重归还对象
  };
  template <typename T,int k=16>  
  class TObjectPool
  {
  private:
    class page;
  public:
    //proxy classes
    class Ptr
    {      
    public:
      friend class page;

      Ptr():m_p(NULL){}
      ~Ptr(){}
  
      T* operator->()const{return m_p;}
      T& operator*()const{return *m_p;}

      bool is_null()const{return NULL==m_p;}
    private:
      Ptr(T* p){}
      Ptr(const Ptr& rhs){}
      Ptr& operator=(const Ptr& rhs){}

      T* m_p;
    };
  public:
    TObjectPool();
    ~TObjectPool();

    //申请一个对象
    bool operator >>(Ptr& ptr);
    //归还一个对象(注意:归后ptr为NULL值)。
    bool operator <<(Ptr& ptr);
    //获取错误代码
    TObjectPool_error error()const{return m_error;}   
  private:
    class page
    {
    public:
      T        m_objects[k];      //对象数组
      T*        m_objects_statck[k];  //对象堆,堆中存储的是对象指针
      bool      m_objects_idle_flag[k];//对象的空闲标志
      unsigned long  m_statck_top;      //堆顶,当为0时说明对象已用完
      unsigned long  m_object_count;  //对象数量      
      
      page():m_object_count(k)        
      {
        for(m_statck_top=0; m_statck_top<m_object_count; ++m_statck_top)
        {
          m_objects_statck[m_statck_top]=&m_objects[m_statck_top];
          m_objects_idle_flag[m_statck_top]=true;
        }
      }  
      bool is_empty(){return 0==m_statck_top;}
      bool is_full(){return m_statck_top==m_object_count;}
      bool is_member(const Ptr& ptr){return ((&(*ptr)>=m_objects)&&(&(*ptr)<=&m_objects[m_object_count-1]));}
   
      void operator >>(Ptr& ptr)
      {
        --m_statck_top;
        m_objects_idle_flag[m_objects_statck[m_statck_top]-m_objects]=false;
        ptr.m_p=m_objects_statck[m_statck_top];
      }

      TObjectPool_error operator <<(Ptr& ptr)
      {
        T* p=ptr.m_p;
        long a=p-m_objects;
        long b=(long)p-(long)m_objects;
        if((b%sizeof(T))!=0)return TObjectPool_error_null_pointer;
        if(is_full()||m_objects_idle_flag[a])return TObjectPool_error_multiple_return;        
        m_objects_idle_flag[a]=true;
        m_objects_statck[m_statck_top]=p;
        ++m_statck_top;
        ptr.m_p=NULL;
        return TObjectPool_error_no;
      }
    };

    std::list<page*> m_lspage;
    std::list<page*>::iterator m_current_page;
    unsigned long  m_idle_object_count;  //空闲对象数量
    TObjectPool_error  m_error;      //错误代码
  };
  //end

  //////////////////////////////////
  //TObjectPool Class template implement
  //////////////////////////////////////
  template <typename T,int k>
  TObjectPool<T,k>::TObjectPool():m_idle_object_count(0),m_error(TObjectPool_error_no)
  {
    m_lspage.push_back(new page);
    m_current_page=m_lspage.begin();
    m_idle_object_count+=k;
  }  
  
  //函数对象,用于销毁容器中new出来的对象
  struct DeleteObject{
    template<typename T>     
    void operator()(T* p)const{delete p;}
  };
  template <typename T,int k>
  TObjectPool<T,k>::~TObjectPool(){std::for_each(m_lspage.begin(), m_lspage.end(),DeleteObject());}
  
  template <typename T,int k>
  bool TObjectPool<T,k>:perator >>(TObjectPool<T,k>:tr& ptr)
  {
    if(m_error!=TObjectPool_error_no)return false;
    if(!ptr.is_null()){if(!operator <<(ptr))return false;}
   
    std::list<TObjectPool<T,k>::page*>::iterator end=m_current_page;
    for(; m_current_page!=m_lspage.end(); ++m_current_page)
    {
      if(!(*(*m_current_page)).is_empty())  //如果不为空就申请一个对象
      {
        --m_idle_object_count;      //一个对象成功分配,空闲对象数量减1
        (*(*m_current_page))>>(ptr);
        return   true;
      }      
    }
    for(m_current_page=m_lspage.begin(); m_current_page!=end; ++m_current_page)
    {
      if(!(*(*m_current_page)).is_empty())  //如果不为空就申请一个对象
      {
        --m_idle_object_count;      //一个对象成功分配,空闲对象数量减1
        (*(*m_current_page))>>(ptr);
        return   true;
      }      
    }

    //如果循环结束还没找到空闲对象,说明页面已经用完,需要分配新页面
    m_lspage.push_back(new page);
    m_current_page=m_lspage.end();
    --m_current_page;
    m_idle_object_count+=k-1;  //空闲对象数量增加一个页面的数量-1
    (*(*m_current_page))>>(ptr);
    return true;
  }
  
  template <typename T,int k>
  bool TObjectPool<T,k>::operator <<(TObjectPool<T,k>::Ptr& ptr)
  {
    if(m_error!=TObjectPool_error_no)return false;
    if(ptr.is_null())
    {
      m_error=TObjectPool_error_null_pointer;
      return false;
    }
    bool ok=false;
    std::list<TObjectPool<T,k>::page*>::iterator end=m_current_page;
    for(; m_current_page!=m_lspage.end(); ++m_current_page)
    {
      if((*(*m_current_page)).is_member(ptr))//对象是否属于此页
      {
        TObjectPool_error Ret=(*(*m_current_page))<<(ptr);
        if(TObjectPool_error_no!=Ret)
        {
          m_error=Ret;
          return false;
        }
        ++m_idle_object_count;  //一个对象成功归还,空闲对象数量加1
        ok=true;
        break;
      }      
    }
    if(!ok)
    {
      for(m_current_page=m_lspage.begin(); m_current_page!=end; ++m_current_page)
      {
        if((*(*m_current_page)).is_member(ptr))//对象是否属于此页
        {
          TObjectPool_error Ret=(*(*m_current_page))<<(ptr);
          if(TObjectPool_error_no!=Ret)
          {
            m_error=Ret;
            return false;
          }
          ++m_idle_object_count;  //一个对象成功归还,空闲对象数量加1
          ok=true;
          break;
        }      
      }
    }
  
    //如果空闲对象数量大于2倍页面数量,说明空闲对象太多了,需要释放一些以减少内存占用
    if(m_idle_object_count>=(k<<1))
    {
      //遍历页面链表,找出空闲页面并释放
      for(std::list<TObjectPool<T,k>::page*>::iterator i=m_lspage.begin(); i!=m_lspage.end();)
      {
        if((*(*i)).is_full())
        {
          delete *i;
          i=m_lspage.erase(i);
          m_idle_object_count -= k;
        }
        else ++i;
      }
    }
    return true;
  }
  
};

#endif

3

主题

14

帖子

18

积分

新手上路

Rank: 1

积分
18
发表于 2011-8-27 20:07:00 | 显示全部楼层

Re:重构的力量-对象池

if(is_full()||m_objects_idle_flag[a])return TObjectPool_error_multiple_return;

m_objects_idle_flag[a]这个不怕越界吗?

45

主题

157

帖子

169

积分

注册会员

Rank: 2

积分
169
QQ
 楼主| 发表于 2011-8-28 15:40:00 | 显示全部楼层

Re:重构的力量-对象池

m_objects_idle_flag[a]这个不会越界,因为long a=p-m_objects;
如果写成long a=(long)p-(long)m_objects;
就会越界,这是我在VC6.0调试发现的,我也是有点不解,不知在其它编译中是否也一样。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-8 18:09

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表