C++ 内存管理容器设计问题-项需要继承

C++ 内存管理容器设计问题-项需要继承,c++,memory,c++11,unique-ptr,C++,Memory,C++11,Unique Ptr,我正在设计一个内存管理容器,考虑到性能和易用性,特别是对于游戏开发项目 我将从源代码中提取最重要的部分 // Uptr is a typedef for std::unique_ptr class MemoryManageable { bool alive{true}; public: bool isAlive() const { return alive; } }; template<typename T> struct Deleter { bool o

我正在设计一个内存管理容器,考虑到性能和易用性,特别是对于游戏开发项目

我将从源代码中提取最重要的部分

// Uptr is a typedef for std::unique_ptr

class MemoryManageable {
    bool alive{true};
    public: bool isAlive() const { return alive; }
};

template<typename T> struct Deleter {
    bool operator()(const Uptr<T>& mItem) const { return !mItem->isAlive(); } 
};  

template<typename T> class MemoryManager {
    // T is the type of items being stored and must inherit MemoryManageable
    std::vector<Uptr<T>> items; 
    std::vector<T*> toAdd; // will be added to items on the next refresh() call
    Deleter<T> deleter;

    void refresh() { 
        items.erase(std::remove_if(std::begin(items), std::end(items), deleter), std::end(items)); 
        for(const auto& i : toAdd) items.push_back(Uptr<T>(i)); toAdd.clear(); 
    }
    void clear() { items.clear(); toAdd.clear(); }

    // Del sets alive to false, so that the item will be deleted and deallocated on the next refresh() call
    void del(T& mItem) { mItem.alive = false; }

    template<typename TType, typename... TArgs> TType& create(TArgs&&... mArgs) { /* creates a new TType* (derived from T) and puts it in toAdd */ }
    template<typename... TArgs> T& create(TArgs&&... mArgs) { return create<T, TArgs...>(std::forward<TArgs>(mArgs)...); }
}
//Uptr是std::unique\u ptr的类型定义
类内存可管理{
布尔活着{true};
public:bool isAlive()const{return alive;}
};
模板结构删除器{
bool操作符()(const Uptr&mItem)const{return!mItem->isAlive();}
};  
模板类内存管理器{
//T是要存储的项的类型,必须继承MemoryManagable
向量项;
std::vector toAdd;//将在下一次refresh()调用时添加到项中
删除器删除器;
无效刷新(){
删除(std::remove_if(std::begin(items)、std::end(items)、deleter)、std::end(items));
对于(const auto&i:toAdd)项。向后推(Uptr(i));toAdd.clear();
}
void clear(){items.clear();toAdd.clear();}
//Del将alive设置为false,以便在下次调用refresh()时删除并释放该项
void del(T&mItem){mItem.alive=false;}
模板TType&create(targets&&…mArgs){/*创建一个新的TType*(从T派生)并将其放入toAdd*/}
模板T&create(TArgs&&…mArgs){return create(std::forward(mArgs)…);}
}

所需的用法如下所示:

struct Entity : public MemoryManageable { 
     Manager& manager; 
     void destroy() { manager.del(*this); } 
     ... 
}

struct Mnnager { 
    MemoryManager<Entity> mm; 
    void del(Entity& mEntity) { mm.del(mEntity); }
    ... 
 }

Manager::update() {
    mm.refresh(); // entities with 'alive == false' are deallocated, and entities in 'mm.toAdd' are added to 'mm.items' 
    for(auto& entity : mm) entity->update(); // entities 'die' here, setting their 'alive' to false 
}
struct实体:公共内存可管理{
经理&经理;
void destroy(){manager.del(*this);}
... 
}
结构管理器{
内存管理器mm;
void del(实体和元素){mm.del(元素);}
... 
}
管理器::更新(){
mm.refresh();//释放'alive==false'的实体,“mm.toAdd”中的实体添加到'mm.items'
对于(auto&entity:mm)entity->update();//此处的实体为'die',将其'alive'设置为false
}
这种带有
refresh()
的延迟插入设计有一些很大的优点:

  • 很快
  • 一个实体即使已经死了也可以被“杀死”
  • 可以从其他实体创建实体,因为在调用
    populate()
    之前,实体不会直接存储在项中
但是,如果不需要继承
memorymanageble
,如果有一种更优雅的方法来删除实体,我会很高兴

  • 有没有一种方法可以让
    MemoryManager
    在内部处理
    活动的
    bool,而不必继承
    memorymanageble
    ,最重要的是,不需要任何性能开销?
  • 是否有一种更优雅的方法可用于删除由
    MemoryManager处理的项目?
理想情况下,由
内存管理器处理的项目应该对此一无所知



用法示例:在gamedev中,实体在更新过程中被破坏是很常见的。考虑一个“int”生命成员的“敌人”实体:<代码>(生命毁灭)()
-这在更新循环期间很容易发生,如果实体在销毁时立即从管理器中删除,则会导致循环和指向死实体的其他实体出现问题。

首先要说的是:我不太喜欢C++11,所以我编写的代码中可能有一些语法错误,但这是逻辑在一些问题上

如果我理解了您的问题,您只希望能够从容器中异步添加和删除项,而不让那些人知道它们的状态。在这种情况下,您可以使用
std::map,bool>
来处理项的状态:
true
=alive,
false
=dead

内存管理器类 字段:

  • std::vectorm_toAdd
    ,一种尚未添加项的向量
  • std::map,bool>m_项目
    ,一个包含每个管理项目和一个
    bool
    标志的映射
方法:

  • add()
    ,它在
    m\u toAdd
    向量中添加一个新项
  • del()
    ,使用其标志在
    m_items
    中标记要删除的项目
  • refresh()
    ,它删除死项并将
    m\u添加到
    m\u items
    中的活动项,然后清除向量
元素类 字段:

  • 内存管理器&m_管理器
    ,对其内存管理器的引用
方法:

  • Elem()
    ,ctor,它调用
    mu管理器::add()
  • del()
    ,它调用
    m\u管理器::del()
创造 当创建
Elem
时,它会自动将自身添加到其内存管理器中,内存管理器会将其添加到
m_toAdd
向量中,然后当所有内容都刷新时,该向量中的
Elem
将在
std::map
中传递,并与
true
布尔值配对(最初标记为活动)

删除 当一个
Elem
要被删除时,它调用其管理器的
del()
方法,该方法在其
std::map
中简单地将其标记为dead,然后当所有内容都被刷新时,管理器中标记为dead的每个
Elem
都被删除,并且
m\u toAdd
向量被清除

(我还建议您使用
std::enable_shared_from_this
,以便更好地处理ptr,但您必须使用
std::shared_ptr
,而不是
std::unique_ptr
,但这不会太糟糕。)

我的建议是:

template< class T >
class MemoryManager
{
   typedef std::unique_ptr< T > unique_t;
   typedef std::map< unique_t, bool > map_t;
   typedef std::pair< unique_t, bool > pair_t;
   typedef std::vector< T * > vector_t;

public:
   void add(T * item)
   {
      m_toAdd.push_back(item);
   }

   void remove(T & item)
   {
      typename map_t::iterator it = m_items.find(item);
      if (it != m_items.end() )(* it).second = false;
   }

   void refresh()
   {
      // clear dead
      typename map_t::iterator it = m_items.begin();
      while ((it = std::find_if(it, m_items.end(), isDead)) != m_items.end())
      {
         m_items.erase(it++);
      }

      // add new
      for(T & item : m_toAdd)
      {
         m_items.insert(std::make_pair(unique_t(item), true));
      }
      m_toAdd.clear();
   }

   void clear()
   {
      m_items.clear();
      m_toAdd.clear();
   }

protected:
   bool isDead(pair_t itemPair)
   {
      // true = alive, false = dead
      return itemPair.second;
   }

private:
   map_t m_items;
   vector_t m_toAdd;
};

class Entity
{
public:
   Entity(MemoryManager< Entity > & manager)
      : m_manager(manager)
   {
      m_manager.add(this);
   }

   void die()
   {
      m_manager.remove(this);
   }

private:
   MemoryManager< Entity > & m_manager;
}; 
模板
类内存管理器
{
typedef std::unique_ptrunique_T;
typedef std::mapmap\t;
typedef std::pairpair\u t;
typedef std::vectorvector\u T;
公众:
无效添加(T*项)
{
m_to add.push_back(项目);
}
无效删除(T和项目)
{
typename map\u t::迭代器it=m\u items.find(item);
如果(it!=m_items.end())(*it).secon
class Entity{ 
public:
  void destroy(){ dead = true; }
  bool isDead(){ return dead; }
private:
  bool dead{false};
};


struct EntityPred{
  bool operator ()(const Entity* p){
    return p->isDead();
  }
};

template<typename T, typename T_PRED>
class MemoryManager{
  // Deletion and insertion is faster to a list than a vector 
  // since deletion of entites[0] requires v.size() - 1 copy constructions.
  // If you really worry about performance (I wouldn't until I have profiled)
  // you can use a memory pool allocator for this.
  std::list<std::unique_ptr<T> > entities;
  // Buffering up many objects that are deleted sequentially is 
  // faster in a vector, less calls to new/delete.
  // But, a pool backed list might be even faster if you're micro optimizing.
  std::vector<T*> toAdd;

public:
  void add(T* p){ toAdd.push_back(p); }

  void refresh(){
    for(auto it = entities.begin(); it != entities.end();){
      if( T_PRED(it) )
        it = entities.erase(it);
      else
        it++;
    }
    // Avoid growing the vector inside the loop since we know the size.
    entities.reserve(entities.size() + toAdd.size());
    for(auto it : toAdd){
      entities.push_back(std::unique_ptr<T>(*it));
    }
    toAdd.clear();
  }
};

MemoryManager<Entity, EntityPred> mgr;
#include <memory>
#include <utility>
#include <list>
#include <string>
#include <iostream>

class Entity{
public:
  Entity(const std::string& msg){ m=msg;};

  // Move constructor required
  Entity(Entity&& that){
    std::swap(m, that.m);
    c = that.c;
  }

  // Should be virtual
  virtual ~Entity(){}; 

  // Do this to release it. 
  void suicide(){  delete this; }

  // Not needed, deleted for safety
  Entity(const Entity&) = delete;
  void operator = (const Entity&) = delete;

  void print(){
    std::cout<<m<<" "<<c<<std::endl;
    c++;
  }

private:
  std::string m;
  int c{0};
};

template<typename T>
class MemoryManager;

template<typename T>
class MemoryObject{
public:
  MemoryObject(MemoryManager<T>* _mgr) : mgr(_mgr) {}
  MemoryObject(MemoryObject&& that){
    mgr = that.mgr;
  }
  MemoryObject(const MemoryObject& that){
    mgr = that.mgr;
  }
  virtual ~MemoryObject(){}
  void operator = (const MemoryObject&) = delete;

  bool isDead(){ return is_dead; }

  friend void swap(MemoryObject& a, MemoryObject& b){
    std::swap(a.mgr, b.mgr);
    std::swap(a.is_dead, b.is_dead);
  }
protected:
  bool is_dead;
  MemoryManager<T>* mgr;
};

template<typename T>
class LiveMemoryObject : public MemoryObject<T>, public T {
public:
  template<typename... ARGS>
  LiveMemoryObject(MemoryManager<T>* _mgr, const ARGS&... args) 
    : MemoryObject<T>(_mgr), T(args...)
  {}
  LiveMemoryObject(const LiveMemoryObject&) = delete;
  LiveMemoryObject(LiveMemoryObject&& other) = delete;
  virtual ~LiveMemoryObject(){
    // Called when Entity did `delete this` but before it is destroyed, 
    // The manager will move construct (swap) a DeadMemoryObject from *this
    // Effectively stealing the contents of Entity before it is destroyed.
    // So when this destructor returns, this object is pointing to a dummy Entity
    // which is destroyed inplace of the original.
    MemoryObject<T>::mgr->remove(this);
  }
  void operator = (const LiveMemoryObject&) = delete;
};

template<typename T>
class DeadMemoryObject : public MemoryObject<T>, public T {
public:
  DeadMemoryObject() = delete;
  DeadMemoryObject(const DeadMemoryObject&) = delete;
  DeadMemoryObject(LiveMemoryObject<T>&& that) 
    : MemoryObject<T>(that), T(static_cast<T&&>(that))
  {
    MemoryObject<T>::is_dead = true;
  }
  virtual ~DeadMemoryObject(){ /* May you finally R.I.P. Entity! */ }
  void operator = (const DeadMemoryObject&) = delete;
};


template<typename T>
class MemoryManager{
private:
  friend class LiveMemoryObject<T>;

  class Handle{
  public:
    template<typename... ARGS>
    explicit Handle(MemoryManager* mgr, const ARGS&... args)
    {
      auto o = new LiveMemoryObject<T>(mgr, args...);
      data = o;
      ptr = o;
    }

    ~Handle(){
      delete data;
    }

    T* operator -> (){ 
      return ptr; 
    }
    const T* operator -> () const { 
      return ptr; 
    }
  private:
    void ageData(){
      auto p = new DeadMemoryObject<T>(std::move(*dynamic_cast<LiveMemoryObject<T>*>(data)));
      data = p;
      ptr = p;
    }

    friend class MemoryManager;
    MemoryObject<T>* data; // Memory owned by handle
    T* ptr; // ease of access to T* of data.
  };

  typedef std::shared_ptr<Handle> HandlePtr;

  std::list<HandlePtr> items;
  std::list<HandlePtr> to_add;

  void remove(LiveMemoryObject<T>* p){
    for(auto it = items.begin(); it != items.end(); ++it){
      if( (*it)->data == p ){
    (*it)->ageData();
    break;
      }
    }
  }

public:
  template<typename... ARGS>
  HandlePtr create(const ARGS&... args){ 
    HandlePtr h{std::make_shared<Handle>(this, args...)};
    to_add.push_back(h);
    return h;
  }

  void refresh(){
    for(auto it  = items.begin(); it != items.end();){
      if((*it)->data->isDead()){
    delete (*it)->data;
    (*it)->data = nullptr;
    (*it)->ptr = nullptr;
    it = items.erase(it);
      }
      else
    it++;
    }
    for(auto it : to_add){
      items.push_back(it);
    }
  }
};

int main(){
  MemoryManager<Entity> mgr;
  auto e = mgr.create("Hello world!");
  mgr.refresh();
  (*e)->print(); // "Hello world! 0"
  (*e)->print(); // "Hello world! 1"
  (*e)->suicide();
  // The object is still valid, we have not called refresh() yet to destroy it.
  (*e)->print(); // "Hello world! 2"

  mgr.refresh();
  (*e)->print(); // Expected sig fault as object has been removed
  return 0;
}