我已经创建了一个MemoryManager< T>这个类基本上是围绕两个向量的指针来包装的,这些指针管理堆分配对象的生命周期.
一个向量存储“活着”对象,另一个向量存储将被添加到下一个MemoryManager< T> ::刷新的对象.
选择该设计以避免在循环遍历MemoryManager T时的迭代器无效,因为直接将新对象直接添加到MemoryManager< T> :: alive向量可以使现有迭代器(如果其大小增加)失效.
template<typename T> struct MemoryManager { std::vector<std::unique_ptr<T>> alive; std::vector<T*> toAdd; T& create() { auto r(new T); toAdd.push_back(r); return *r; } T& refresh() { // Use erase-remove idiom on dead objects eraseRemoveIf(alive,[](const std::unique_ptr<T>& p){ return p->alive; }); // Add all "toAdd" objects and clear the "toAdd" vector for(auto i : toAdd) alive.emplace_back(i); toAdd.clear(); } void kill(T& mItem) { mItem.alive = false; } IteratorType begin() { return alive.begin(); } IteratorType end() { return alive.end(); } }
我在游戏引擎中使用它来存储实体,并且每帧更新每个“活着”实体:
void game() { MemoryManager<Entity> mm; while(gameLoop) { mm.refresh(); for(auto e : mm) processEntity(e); auto& newEntity = mm.create(); // do something with newEntity } }
这让我经常创建/杀死实体,而不用担心他们的一生的太多.
不过,我最近得出的结论是,使用两个std :: vector是不必要的.我可以简单地使用单个向量并将迭代器存储到“最后一个活动对象”中,在上述迭代器之后立即添加新创建的对象:
在我看来,这个想法很好,但实际上我不能使用迭代器类型作为结束(如图所示),因为它可能会在向量中添加一些新元素后失效.我已经测试过,这种情况经常发生,导致崩溃.
我可以想到的另一个解决方案是使用索引而不是迭代器.这将解决崩溃,但是由于MemoryManager> :: begin和MemoryManager< T> :: end需要返回一个迭代器,所以我不能使用酷的C 11 for(x:y)foreach循环.
有没有办法用单个向量来实现当前的行为,并且仍然保持一个清晰的界面,可以用于C 11 for-each循环?
解决方法
您可以实现自己的迭代器类.
以下可能有帮助.
template <typename T,typename... Ts> class IndexIterator : public std::iterator<std::random_access_iterator_tag,T> { public: IndexIterator(std::vector<T,Ts...>& v,std::size_t index) : v(&v),index(index) {} // if needed. typename std::vector<T,Ts...>::iterator getRegularIterator() const { return v->begin() + index; } T& operator *() const { return v->at(index); } T* operator ->() const { return &v->at(index); } IndexIterator& operator ++() { ++index; return *this;} IndexIterator& operator ++(int) { IndexIterator old(*this); ++*this; return old;} IndexIterator& operator +=(std::ptrdiff_t offset) { index += offset; return *this;} IndexIterator operator +(std::ptrdiff_t offset) const { IndexIterator res (*this); res += offset; return res;} IndexIterator& operator --() { --index; return *this;} IndexIterator& operator --(int) { IndexIterator old(*this); --*this; return old;} IndexIterator& operator -=(std::ptrdiff_t offset) { index -= offset; return *this;} IndexIterator operator -(std::ptrdiff_t offset) const { IndexIterator res (*this); res -= offset; return res;} std::ptrdiff_t operator -(const IndexIterator& rhs) const { assert(v == rhs.v); return index - rhs.index; } bool operator == (const IndexIterator& rhs) const { assert(v == rhs.v); return index == rhs.index; } bool operator != (const IndexIterator& rhs) const { return !(*this == rhs); } private: std::vector<T,Ts...>* v; std::size_t index; }; template <typename T,typename... Ts> IndexIterator<T,Ts...> IndexIteratorBegin(std::vector<T,Ts...>& v) { return IndexIterator<T,Ts...>(v,0); } template <typename T,Ts...> IndexIteratorEnd(std::vector<T,v.size()); }