首页 > 解决方案 > c ++可靠的方法来删除以UUID为键的所有条目

问题描述

所以我有一堆 std::unordered_maps,它们都有一个共同的键,但数据的数据类型不同。我基本上做了一个类似于基于组件的实体系统的结构,关键是一个包含 boost::uuid 的实体类。

添加效果很好,但我正在努力从程序中删除整个实体。我找不到在不损害正在运行的系统的情况下删除它们的可靠方法(我不想允许在帧中间删除以避免由于值不同步或被某些默认值替换而导致一帧出现故障)或这太慢了。

现在我在实体类中有一个布尔值,程序的每一帧都会遍历每个实体并检查它是否设置为真。如果是,则从地图中删除数据点。

然而我对此并不满意。

这是一般实体的样子:

    class Entity{
private:
    boost::uuids::uuid uuid;
    bool protect = false;
    bool status = ENTITY_ALIVE;
public:
    Entity()
    :uuid(boost::uuids::random_generator()()){
    }
    const boost::uuids::uuid &operator ()()const{
        return this->uuid;
    }
    bool operator ==(const Entity &othr)const{
        return this->uuid==othr.uuid;
    }


    void copyComponents(const Entity &source,ComponentBase** mgrs, int c){
        std::cout<<"copying...\n";
        for(int i = 0; i < c; i ++){
            std::cout<<"-";
            mgrs[i]->copyTo(source,*this);
        }
    }
    void kill(){
        if(this->protect==false){
            this->status = ENTITY_DEAD;
        }
    }
    bool getStatus()const{
        return this->status;
    }
    void setProtection(bool status){
        this->protect = status;
    }

    bool getProtection(){
        return this->protect;
    }

    ~Entity(){
//        std::cout<<"ENTITY WAS DELETED!!!!!!!!!!!"<<"\n";
    }
};
struct EntityHasher{
    size_t operator()(const Entity& obj)const{
        return boost::uuids::hash_value((obj)());
    }

};

好的,这就是地图的样子:

typedef typename std::unordered_map<std::reference_wrapper<const Entity>,List<std::shared_ptr<t>>,EntityHasher,std::equal_to<const Entity>> mapType;

该列表是我制作的一个自定义类,它只是将事物存储在一个双向链表中。没什么好担心的。我这样做是因为访问数据比使用 unordered_multi 地图更容易。

我试过的:

请提出一些好的方法来删除所有地图中的实体,并将其作为键,而不会弄乱活动框架等。

标签: c++components

解决方案


您可以使用 Boost.MultiIndex 来构建一个类似地图的结构,使尸体首先排列在二级排序索引中,以便在适当的时候将其擦除:

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/member.hpp>

template<typename Key,typename Value>
struct delayed_erasure_unordered_map_value
{
  Key           first;
  mutable Value second;
};

template<typename Key,typename Value>
using delayed_erasure_unordered_map_base=boost::multi_index_container<
  delayed_erasure_unordered_map_value<Key,Value>,
  boost::multi_index::indexed_by<
    boost::multi_index::hashed_unique<
      boost::multi_index::member<
        delayed_erasure_unordered_map_value<Key,Value>,
        Key,
        &delayed_erasure_unordered_map_value<Key,Value>::first
      >
    >,
    boost::multi_index::sequenced<>
  >
>;

template<typename Key,typename Value>
class delayed_erasure_unordered_map:
  public delayed_erasure_unordered_map_base<Key,Value>
{
  using base=delayed_erasure_unordered_map_base<Key,Value>;
public:
  using iterator=typename base::iterator;

  using base::base;

  void mark_for_erasure(iterator it) // marking same element twice is UB
  {
    auto pit=this->template project<1>(it);
    auto& index=this->template get<1>();
    index.relocate(index.begin(),pit);
    ++num_corpses;
  }

  void erase_marked()
  {
    auto& index=this->template get<1>();
    for(;num_corpses;--num_corpses)index.erase(index.begin());
  }

private:
  std::size_t num_corpses=0;
};

#include <iostream>

int main()
{
  delayed_erasure_unordered_map<int,int> m=
    {{0,0},{1,1},{2,2},{3,3},{4,4},{5,5},{6,6},{7,7},{8,8},{9,9}};

  for(auto it=m.begin(),end=m.end();it!=end;++it){
    if(it->first%2)m.mark_for_erasure(it);
  }
  m.erase_marked();

  for(const auto& x:m){
    std::cout<<"{"<<x.first<<","<<x.second<<"} ";
  }
}

输出

{0,0} {2,2} {4,4} {6,6} {8,8} 

推荐阅读