2012-05-31 105 views
0

仍然深入研究C++/boost,以便歡迎任何意見/反饋。固定大小的多索引多態容器提升多索引

我在玩boost :: unordered_maps,並創建了一個使用形狀的多態示例,關於我頭腦 纏繞(大部分)的時間,我偶然發現了boost multi_index的mru示例。 http://www.boost.org/doc/libs/1_46_1/libs/multi_index/example/serialization.cpp

那時我想。嗯,一個固定大小的多索引多態容器,將丟棄基於 LRU的值,這聽起來很瘋狂而不實現。

#include <boost/multi_index_container.hpp> 
    #include <boost/multi_index/hashed_index.hpp> 
    #include <boost/multi_index/identity.hpp> 
    #include <boost/multi_index/sequenced_index.hpp> 
    #include <boost/shared_ptr.hpp> 
    #include <boost/tuple/tuple.hpp> 
    #include "boost/tuple/tuple_comparison.hpp" 

    enum shape_returns { 
     SHAPE_ERROR = -1, 
     SHAPE_OK = 0 
    }; 

    // coordinates 
    typedef boost::tuples::tuple<int, int, int> ShapeKey; 

    class Shape { 
    public: 
     Shape() : pos() {} 
     ~Shape() {} 

     virtual int draw() { return SHAPE_ERROR; } 

     ShapeKey pos; 
    }; 
    typedef boost::shared_ptr<Shape> Shape_ptr; 

    class Circle : public Shape { 
    public: 
     Circle() {} 
     ~Circle() {} 

     int radius; 

     virtual int draw() { /* draw stuff */ return SHAPE_OK; } 
    }; 
    typedef boost::shared_ptr<Circle> Circle_ptr; 

    class Square : public Shape { 
    public: 
     Square() {} 
     ~Square() {} 

     int len; 

     virtual int draw() { /* draw stuff */ return SHAPE_OK; } 
    }; 
    typedef boost::shared_ptr<Square> Square_ptr; 

    using namespace boost::multi_index; 

    // multi index tags 
    struct seq {}; 
    struct hash {}; 

    class ShapesLRU { 
     typedef boost::multi_index::multi_index_container< 
      Shape_ptr, 
      boost::multi_index::indexed_by< 
      boost::multi_index::sequenced<boost::multi_index::tag<seq> >, 
      boost::multi_index::hashed_unique< 
       boost::multi_index::tag<hash>, 
       boost::multi_index::identity<Shape_ptr> 
      > 
      > 
     > shapes_list; 

    public: 
     typedef typename shapes_list::iterator iterator; 
     typedef typename boost::multi_index::index<shapes_list, seq>::type seq_index; 
     typedef typename boost::multi_index::index<shapes_list, hash>::type hashed_index; 

     ShapesLRU (std::size_t max) : max_shapes(max) {} 
     ~ShapesLRU() {} 

     void insert(const Shape_ptr item) 
     { 
      std::pair<typename shapes_list::iterator, bool> ret = shapes.push_front(item); 

      if (!ret.second) { 
       // new item may be different 
       erase(item->pos); 
       ret = shapes.push_front(item); 
      } else if (shapes.size() > max_shapes) { 
       shapes.pop_back(); 
      } 
     } 

     typename shapes_list::iterator begin() { return shapes.begin(); } 
     typename shapes_list::iterator end() { return shapes.end(); } 

     typename hashed_index::iterator hash_begin() { return shapes.get<hash>().begin(); } 
     typename hashed_index::iterator hash_end() { return shapes.get<hash>().end(); } 

     typename hashed_index::iterator find(const ShapeKey &key) 
     { 
      Shape_ptr tmp(new Shape()); 
      tmp->pos = key; 

      // XXX why compiler error w/o "using namespace boost::multi_index" 
      return shapes.get<hash>().find(tmp); 
     } 

     void erase(const ShapeKey &key) 
     { 
      typename hashed_index::iterator itr = find(key); 
      // XXX why compiler error w/o "using namespace boost::multi_index" 
      shapes.get<hash>().erase(itr); 
     } 

    private: 
     // The multi-indexed data store 
     shapes_list shapes; 

     // The size of the data store 
     std::size_t max_shapes; 
    }; 

    inline std::size_t 
    hash_value(const Shape_ptr shape) 
    { 
     std::size_t seed = 0; 

     boost::hash_combine(seed, shape->pos.get<0>()); 
     boost::hash_combine(seed, shape->pos.get<1>()); 
     boost::hash_combine(seed, shape->pos.get<2>()); 

     return seed; 
    } 

    int 
    main() 
    { 
     ShapesLRU shapes(10); 

     Circle_ptr cptr1(new Circle()); 
     ShapeKey pos1(1, 1, 1); 
     cptr1->pos = pos1; 
     cptr1->radius = 1; 

     Circle_ptr cptr2(new Circle()); 
     ShapeKey pos2(2, 2, 2); 
     cptr2->radius = 2; 
     cptr2->pos = pos2; 

     shapes.insert(cptr1); 

     ShapesLRU::hashed_index::iterator itr = shapes.find(pos1); 

     return 0; 
    } 

經過大量的工作後,我仍然留下以下問題。

  1. 在插入

    ()是有辦法從序列 迭代得到hashed_unique迭代器,所以我可以直接調用抹去?

  2. 有沒有更好的方法實現查找?如果我只用鍵就可以找到類似 的boost :: unordered_map,而不必爲查找創建一個虛擬的 形狀。

  3. 獲得<>的正確途徑是什麼(請參閱代碼XXX中的評論)我嘗試了一切,我是正確的,然後開始嘗試隨機廢話,沒有任何擺脫。

  4. 我真的想一[]操作,但我認爲這是長的路...... 形狀[cptr1-> POS] = cptr1;

  5. 如何從我的hash_index :: iterator中獲得項目(或通常意義上的這個項目),打印它當然沒有幫助...

p ITR $ 1 = {,性病::分配器>>>,升壓:: multi_index ::詳細:: bucket_array>>>,升壓:: shared_ptr的,長,提高:: shared_ptr的常量*, boost :: shared_ptr const & >> = {,std :: allocator>>>,boost :: multi_index :: detail :: bucket_array>>>,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr的常量*,升壓:: shared_ptr的常量&> >> = {,性病::分配器>>>,升壓:: multi_index ::詳細:: bucket_array>>>,升壓:: shared_ptr的常量*,升壓:迭代, long,boost :: shared_ptr const *,boost :: shared_ptr const &> >> = {,std :: allocator>>>,boost :: multi_index :: detail :: bucket_array>>>,boost :: incrementable,std: :allocator> >>,boost :: multi_index :: det ail :: bucket_array>>,boost :: dereferenceable,std :: allocator>>>,boost :: multi_index :: detail :: bucket_array>>,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr的常量*,升壓:: shared_ptr的常量&>>> >> = {,性病::分配器>>>,升壓:: multi_index ::詳細:: bucket_array>>>,升壓::提領,性病::分配器>>>,提振:: multi_index ::詳細:: bucket_array>>>,提高:: shared_ptr的常量*,提振::迭代器,長,提高:: shared_ptr的常量*,提高:: shared_ptr的常量&>> >> = {,std :: allocator>>>,boost :: multi_index :: detail :: bucket_array>>>,boost :: shared_ptr const *,boost :: iterator,long,boost :: shared_ptr const *,boost :: shared_ptr常量&> >> = {,長,提高:: shared_ptr的常量*,提高:: shared_ptr的常量& >> = {,長,提高:: shared_ptr的常量*,提高:: shared_ptr的常量& >> = {,長,提高:: shared_p TR常量*,升壓:: shared_ptr的常量& >> = {},},},},},},},},},節點= 0x60a010,水桶= 0x7fffffffdd88}

回答

1

在插入件()有沒有辦法從 序列迭代器中獲得hashed_unique迭代器,所以我可以直接調用erase?

請參閱iterator projection

有沒有更好的辦法工具找到?這很好,如果我可以用找到像boost :: unordered_map那樣的密鑰,而不是讓 爲查找創建一個虛擬形狀。

首先,我認爲你目前的實現是錯誤的:你的散列索引是基於Shape_ptr平等,後 - 您希望根據Shape::ShapeKey平等這是不是你的東西。爲了得到這一點,只需重新定義索引

boost::multi_index::hashed_unique< 
    boost::multi_index::tag<hash>, 
    boost::multi_index::member<Shape,ShapeKey,&Shape::pos> 
> 

對於這個工作,你必須實現的哈希爲ShapeKey,留給:-)現在實施find演習是

hashed_index::iterator find(const ShapeKey &key) 
{ 
    return shapes.get<hash>().find(key); 
} 
一樣簡單

是什麼讓<>(參見代碼XXX評論)我試過 一切,我是正確的,然後就開始嘗試隨機廢話, 從來都沒有搖出正確的路徑。

我不明白爲什麼你的語法是行不通的。這應該。

我真的很喜歡[]運算符,但我認爲這是一種方式... ... shapes [cptr1-> pos] = cptr1;

指數Boost.MultiIndex中被std::setstd::unordered_set,而不是std::mapstd::unordered_map模仿(爲根本原因,我們不必在這裏討論。)但是,認爲這是一個map<T,Q>是一個很值得set<mutable_pair<T,Q>>,其中mutable_pair是一對結構其第二位成員是mutable。你可以利用這個等價性來構建帶有Boost.MultiIndex的類地圖結構。

怎樣才能獲得該項目(或使這個在一般意義上)從我hash_index:迭代,打印它肯定沒有幫助...

你是什麼意思「印刷「?

+0

投影!甜心的感謝 另外我以前的散列索引是有點作弊,如果你仔細觀察我是基於ptr散列,但是,我重寫Shape_ptr hash_value返回ShapeKey的hash_value。最終它並不重要,你的解決方案非常好。我不認爲boost :: multi_index :: member 可以工作,因爲存儲的項目是boost :: shared_ptr user442585

+0

Shape_ptr上的索引問題是,當您想要找到具有給定鍵的元素時,您需要構造一個虛擬的Shape_ptr;在ShapeKey上建立索引可以讓你直接使用這個鍵而不用麻煩。 –