带有池的模板化抽象工厂类

发布于 2024-10-25 20:32:11 字数 2591 浏览 1 评论 0原文

我正在开发一个处理事件的游戏引擎组件。我想做的是创建一个可以按名称注册新事件类型的系统。然后,事件管理器将保存事件类型和工厂的集合来生成此类事件类型,但不同之处在于我想让它使用池系统,以便我创建一个事件,使用它,然后而不是删除它,将其放入列表中。下次我创建该事件时,我可以从池中分配,而不是使用堆。

所以给定这些事件类型的层次结构...

struct TEvent
{
  int nID;
  int nTimeStamp;
};

struct TCollisionEvent : public TEvent
{
  TEntity* pEntity1;
  TEntity* pEntity2;
  Vector3* pvecPoint;
};

然后我创建了一个智能工厂来执行此创建/回收操作:

template <class BASE_CLASS>
class CSmartFactory
{
private:
  typedef typename std::list<BASE_CLASS*> TBaseList;
  typedef typename std::list<BASE_CLASS*>::iterator TBaseListItr;

  TBaseList* m_plstPool;

public:
  explicit CSmartFactory()
  {
    m_plstPool = NULL;
  }

  ~CSmartFactory()
  {
    TBaseListItr itr;

    if (m_plstPool)
    {
      for (itr = m_plstPool->begin(); itr != m_plstPool->end(); itr++)
      {
        BASE_CLASS* pEntity = *itr;
        SAFE_DELETE(pEntity);
      }

      m_plstPool->clear();
      SAFE_DELETE(m_plstPool);
    }    
  }

  bool Init(int nPoolSize)
  {
    bool bReturn = false;

    do 
    { 
      m_plstPool = new TBaseList;
      IwAssert(MAIN, m_plstPool);

      while (nPoolSize--)
      {
        BASE_CLASS* pBaseObject = new BASE_CLASS;
        IwAssert(MAIN, pBaseObject);

        m_plstPool->push_back(pBaseObject);
      }

      bReturn = true;
    } while(0); 

    return bReturn; 
  }

  BASE_CLASS* Create()
  {
    BASE_CLASS* pBaseObject = NULL;

    //
    // grab a pre-made entity from the pool or allocate a new one
    if (m_plstPool->size() > 0)
    {
      pBaseObject = m_plstPool->front();
      m_plstPool->pop_front();
      pBaseObject->Clear();
    }
    else
    {
      pBaseObject = new BASE_CLASS;
      IwAssert(MAIN, pBaseObject);
    }

    return pBaseObject;
  }

  void Recycle(BASE_CLASS* pBaseObject)
  {
    m_plstPool->push_back(pBaseObject);
  }
};

所以现在我可以这样做:

CSmartFactory<TCollisionEvent>* pCollisionEventFactory = new CSmartFactory<TCollisionEvent>;

但是我想要做的是让我的事件管理器允许动态事件注册,但这就是我遇到了障碍。

理想情况下,RegisterEvent 将跟踪 stl::map 或其他内容中的名称和工厂指针,但不太确定如何到达该点。也许我完全走错了路。

这个编译

class TEventManager
{
public:
  TEventManager();
  ~TEventManager();

  bool RegisterEvent(char* pszEventName, CSmartFactory<TEvent>* pFactory);
};

直到你添加

TEventManager::RegisterEvent("CollisionEvent", new CSmartFactory<TEntityCollisionEvent>);

所以现在我绝望地试图找到一种方法来使这一切工作。

有人在这里有一些想法吗?

弗雷德

I'm working on a game engine component that handles events. What I'm trying to do is create a system that I can register new event types by name. The event manager will then hold a collection of event types and the factories to generate such an event type BUT the twist is that I want to make it used a pooling system such that I create an event, use it and then rather than deleting it, throw it into a list. Next time I create that event, rather than using the heap, I can just allocate from the pool.

SO given these hierarchy of event types...

struct TEvent
{
  int nID;
  int nTimeStamp;
};

struct TCollisionEvent : public TEvent
{
  TEntity* pEntity1;
  TEntity* pEntity2;
  Vector3* pvecPoint;
};

I then created a smart factory which does this creation/recyling operation:

template <class BASE_CLASS>
class CSmartFactory
{
private:
  typedef typename std::list<BASE_CLASS*> TBaseList;
  typedef typename std::list<BASE_CLASS*>::iterator TBaseListItr;

  TBaseList* m_plstPool;

public:
  explicit CSmartFactory()
  {
    m_plstPool = NULL;
  }

  ~CSmartFactory()
  {
    TBaseListItr itr;

    if (m_plstPool)
    {
      for (itr = m_plstPool->begin(); itr != m_plstPool->end(); itr++)
      {
        BASE_CLASS* pEntity = *itr;
        SAFE_DELETE(pEntity);
      }

      m_plstPool->clear();
      SAFE_DELETE(m_plstPool);
    }    
  }

  bool Init(int nPoolSize)
  {
    bool bReturn = false;

    do 
    { 
      m_plstPool = new TBaseList;
      IwAssert(MAIN, m_plstPool);

      while (nPoolSize--)
      {
        BASE_CLASS* pBaseObject = new BASE_CLASS;
        IwAssert(MAIN, pBaseObject);

        m_plstPool->push_back(pBaseObject);
      }

      bReturn = true;
    } while(0); 

    return bReturn; 
  }

  BASE_CLASS* Create()
  {
    BASE_CLASS* pBaseObject = NULL;

    //
    // grab a pre-made entity from the pool or allocate a new one
    if (m_plstPool->size() > 0)
    {
      pBaseObject = m_plstPool->front();
      m_plstPool->pop_front();
      pBaseObject->Clear();
    }
    else
    {
      pBaseObject = new BASE_CLASS;
      IwAssert(MAIN, pBaseObject);
    }

    return pBaseObject;
  }

  void Recycle(BASE_CLASS* pBaseObject)
  {
    m_plstPool->push_back(pBaseObject);
  }
};

SO now I can do this:

CSmartFactory<TCollisionEvent>* pCollisionEventFactory = new CSmartFactory<TCollisionEvent>;

BUT what I want to do is have my event manager allow for dynamic event registration but that's where I run into my snag.

Ideally RegisterEvent will track the name and factory pointer in an stl::map or something but not quite sure how to get to that point. Maybe I've gone down the wrong path altogether.

This compiles

class TEventManager
{
public:
  TEventManager();
  ~TEventManager();

  bool RegisterEvent(char* pszEventName, CSmartFactory<TEvent>* pFactory);
};

Until you add

TEventManager::RegisterEvent("CollisionEvent", new CSmartFactory<TEntityCollisionEvent>);

So now I'm hopelessly trying to find a way to make this all work.

Anybody got some ideas here!?

Fred

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

万劫不复 2024-11-01 20:32:13

这两个类 CSmartFactoryCSmartFactory 将生成类似

  • CSmartFactory_TEntityCollisionEvent

  • CSmartFactory_TEvent

内容它们实际上是两个独立且不相关的类。尝试互换使用它们是不明智的,尽管它们的行为相同(它们的类型类是多态的)。

动态铸造不起作用,但是您可以尝试使用强力铸造:

TEventManager::RegisterEvent("CollisionEvent", 
        reinterpret_cast<CSmartFactory<TEvent>*>(new CSmartFactory<TEntityCollisionEvent>));

警告:风险自负! ;-)

The two classes CSmartFactory<TEntityCollisionEvent> and CSmartFactory<TEvent> will be generated to something like

  • CSmartFactory_TEntityCollisionEvent

  • CSmartFactory_TEvent

They are actually two separate and unrelated classes. Trying to use them interchangeably would be unwise, although they behave the same (their type classes are polymorphic right).

Dynamic casting wont work, you could however try to use brute force casting:

TEventManager::RegisterEvent("CollisionEvent", 
        reinterpret_cast<CSmartFactory<TEvent>*>(new CSmartFactory<TEntityCollisionEvent>));

Warning: At your own risk! ;-)

你是年少的欢喜 2024-11-01 20:32:13

好吧,经过大量的头脑碰撞后,我意识到解决方案比我试图实现的要简单得多。

管理者应该关心的只是管理 TEvent*。每个 TEvent 都有一个唯一的哈希值,因此当添加新事件时,该事件的字符串名称和哈希名称都会被存储。因此,从那里我可以添加一个指向任何子类的指针,只要它被转换为 TEvent 即可。

我让它变得比需要的复杂得多。

OK so after a lot of head banging, I realized the solution is FAR simpler than what I was trying to pull off.

All the manager should care about is managing a TEvent*. Each TEvent has a unique hash value that makes it unique so when a new event is added both the string name and hash name of that even is stored. So from there I can add a pointer to any subclass so long as it's casted to TEvent.

I was making it FAR more complex than it needed to be.

酒绊 2024-11-01 20:32:12

我假设您想重用事件以避免昂贵的堆 malloc/free ?

我认为正确的答案不是通过编写自己的重用对象结构来使代码变得复杂,而是使用小对象分配器。首先,可能值得研究 boost::池

I assume that you want to reuse events to avoid expensive heap malloc/free's?

I think the right answer here is not to convolute your code by writing your own structure for reusing objects, but to use a small-object allocator. As a start, it may be worth looking into boost::pool.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文