шаблонный абстрактный фабричный класс с пулами - PullRequest
0 голосов
/ 24 марта 2011

Я работаю над компонентом игрового движка, который обрабатывает события.Я пытаюсь создать систему, в которой я могу регистрировать новые типы событий по имени.Менеджер событий затем будет содержать коллекцию типов событий и фабрик для генерации такого типа событий, НО поворот заключается в том, что я хочу, чтобы он использовал систему пула так, чтобы я создавал событие, использовал его, а затем вместо того, чтобы удалять его,бросить его в список.В следующий раз, когда я создаю это событие, вместо использования кучи я могу просто выделить его из пула.

ТАК, учитывая эту иерархию типов событий ...

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>);

Так что теперь я безнадежно пытаюсь найтиспособ заставить все это работать.

Кто-нибудь есть идеи здесь??

Фред

Ответы [ 3 ]

0 голосов
/ 24 марта 2011

Два класса CSmartFactory<TEntityCollisionEvent> и CSmartFactory<TEvent> будут сгенерированы в нечто вроде

  • CSmartFactory_TEntityCollisionEvent

  • CSmartFactory_TEvent

На самом деле это два отдельных и не связанных класса. Пытаться использовать их взаимозаменяемо было бы неразумно, хотя они ведут себя одинаково (их классы типов имеют правильное полиморфное значение).

Динамическое приведение не сработает, однако вы можете попробовать использовать приведение методом грубой силы:

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

Внимание: на свой страх и риск! ; -)

0 голосов
/ 25 марта 2011

ОК, поэтому после большого количества ударов головой я понял, что решение НАМНОГО проще, чем то, что я пытался осуществить.

Все, о чем должен заботиться менеджер - это управление TEvent *. Каждый TEvent имеет уникальное хеш-значение, которое делает его уникальным, поэтому при добавлении нового события сохраняются как строковое имя, так и хеш-имя, которое даже сохраняется. Поэтому я могу добавить указатель на любой подкласс, если он приведен к TEvent.

Я делал это намного сложнее, чем нужно.

0 голосов
/ 24 марта 2011

Я предполагаю, что вы хотите повторно использовать события, чтобы избежать дорогостоящей кучи malloc / free?

Я думаю, что правильный ответ здесь не в том, чтобы свернуть ваш код путем написания собственной структуры для повторного использования объектов, а в использованиираспределитель мелких объектов.Для начала стоит взглянуть на boost :: pool .

...