试图学习boost :: intrusive Q2

时间:2014-11-11 05:02:13

标签: c++ c++11 boost intrusive-containers

如果我取消注释这些

//BaseList   baselist; 
//MemberList memberlist;

在循环之外并注释掉循环中的那些它崩溃了。我需要能够在任何循环之外使用baselist(和memberlist)。这是如何实现的?

修改

  

我想用它解决的实际问题是最简单的形式。

     

我希望有一个MyClass的std :: vector,称之为AllThingsBunchedTogether。   我还想要一个BaseList的std :: vector,称之为AllThingsSpreadOut。

     

所以

     
      
  • AllThingsBunchedTogether可能包含(为了紧凑而只包含anInt1部分):1,2,1,10,2,3,4,4,5,9,10,10
  •   
  • AllThingsSpreadOut可能包含[1] 1,1的[1] 2,2,[3] 3位于[4] 4,4 at {4] 5 at [5] 9位于[9] 10,10,10,位于[10] BaseList
  •   
     

请注意,这些数字本身并不存储在MyClass中,而是存储在BaseList(1," John")中。

     

在[1]它可能是#34; Mike"," John",在[2]它可能是" Mike"," Dagobart&# 34;在[3]   "约翰" ...在[10]" John" "麦克" " Dagobart"等等,以便没有重复   AllThingsSpreadOut [i]中的任何MyClass,因为每个BaseList   anInt1 + Name哈希值为不同的值(anInt1)。

     

实质上,MyClass告诉anInt1 + name在AllThingsSpreadOut中的位置,但BaseList保证每个BaseList内的唯一性。

     

所以我的想法是AllThingsSpreadOut是BaseList的向量,其中向量位置的每个#include <vector> #include <iostream> #include <boost/intrusive/list.hpp> using namespace boost::intrusive; class MyClass : public list_base_hook<link_mode<auto_unlink>> // This is a derivation hook { public: std::string name; bool bIsMarkedToDelete; int anInt1; public: list_member_hook<link_mode<auto_unlink>> member_hook_; // This is a member hook MyClass(std::string n, int i) : name(n), anInt1(i), bIsMarkedToDelete(false) {} }; bool IsMarkedToDelete(const MyClass &o) { return o.bIsMarkedToDelete; } //Define a list that will store MyClass using the public base hook typedef list<MyClass, constant_time_size<false>> BaseList; // Define a list that will store MyClass using the public member hook typedef list<MyClass, member_hook<MyClass, list_member_hook<link_mode<auto_unlink>>, &MyClass::member_hook_>, constant_time_size<false> > MemberList; int main() { bool done = false; std::vector<MyClass> values; std::string names[] = {"John", "Mike", "Dagobart"}; //BaseList baselist; //MemberList memberlist; int i = 0; while(!done) { // Create several MyClass objects, each one with a different value for (int j = 0; j < 11; ++j) values.emplace_back(names[j % 3], j); BaseList baselist; MemberList memberlist; // Now insert them in t-he reverse order in the base hook list for (auto& e : values) { baselist.push_front(e); memberlist.push_back(e); } // Now test lists auto rbit(baselist.rbegin()); auto mit(memberlist.begin()); auto it(values.begin()), itend(values.end()); // Test the objects inserted in the base hook list for (; it != itend; ++it, ++rbit) { if (&*rbit != &*it) return 1; } // Test the objects inserted in the member hook list for (it = values.begin(); it != itend; ++it, ++mit) { if (&*mit != &*it) return 1; } # if 0 for(auto& e : values) std::cout << e.anInt1 << "\n"; for(auto& e : baselist) std::cout << e.anInt1 << "\n"; for(auto& e : memberlist) std::cout << e.anInt1 << "\n"; #endif // 0 if(2 == i) { for(auto& e: values) std::cout << e.name << "\n"; for(auto& e: values) { if("Mike" == e.name) e.bIsMarkedToDelete = true; } values.erase( std::remove_if(values.begin(), values.end(), IsMarkedToDelete), values.end()); } if(i++ > 3) { values.clear(); done = true; } std::cout << "\n"; std::cout << values.size() << "\n"; std::cout << baselist.size() << "\n"; std::cout << memberlist.size() << "\n"; } } 都是类似事物的列表。

     

然后,当我从AllThingsBunchedTogether中删除内容时(不是通过清除,而是通过搜索删除IsMarkedToDelete下面的代码中的某些项目),它们将自动从相应的AllThingsSpreadOut中消失。

     

AllThingsSpreadOut充当AllThingsBunchedTogether的排序,具有侵入性语义。 AllThingsBunchedTogether允许通过[]进行超高速访问。

结束修改

{{1}}

2 个答案:

答案 0 :(得分:5)

我已经看到了很晚,但无论如何,这里是:

  1. 您所描述的内容与完全相同 MyClass元素的侵入式哈希表的实现,其中

    • anInt1是元素的哈希( bucket 标识符)
    • 存储桶列表实现为链接列表
    • 将相等性定义为(anInt1, Name)

      的相等性
        

      enter image description here


    实际上,你的程序只是

    <强> Live On Coliru

    std::unordered_set<MyClass> values {
        { "John",      0 }, { "Mike",      1 }, { "Dagobart",  2 },
        { "John",      3 }, { "Mike",      4 }, { "Dagobart",  5 },
        { "John",      6 }, { "Mike",      7 }, { "Dagobart",  8 },
        { "John",      9 }, { "Mike",     10 },
    };
    
    for(int i = 0; i<=3; ++i) {
        if(2 == i) {
            for(auto& e: values) std::cout << e.name << " "; std::cout << "\n";
            for(auto& e: values) e.bIsMarkedToDelete |= ("Mike" == e.name);
    
            for(auto it=begin(values); it!=end(values);) {
                if (it->bIsMarkedToDelete) it = values.erase(it);
                else ++it;
            }
        }
    
        std::cout << "i=" << i << ", values.size(): " << values.size() << "\n";
    }
    values.clear();
    std::cout << "Done\n";
    
  2. 如果你真的想要连续存储,我只能假设你想要这个性能

    • 想要使用指针而不是对象,因为这只会消除内存布局(“AllThingsBunchedTogether”)的好处,你会更好地使用{{1} }或unordered_set如上

    • 想要使用unodered_map模式,因为它会削弱性能(通过执行不受控制的删除触发器,禁止常量时间auto_unlink并创建线程安全问题)

    • 相反,您应该使用上述战略,但使用size()代替http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive/unordered_set_unordered_multiset.html

      这里再次是一个概念验证:

      <强> Live On Coliru

      boost::intrusive::unordered_set

答案 1 :(得分:0)

这是您忽略的错误消息:

Assertion `node_algorithms::inited(to_insert)' failed.

由此我们可以理解,元素被插入两次。这对于侵入式容器一般无效。

当你在循环中有你的列表时,它们每次都会被销毁并重新创建。但是当他们在外面时,你永远不会清除它们,而且你也永远不会清除values,所以这个顺序发生了:

  1. values添加11个元素。
  2. 将所有values添加到列表中。
  3. values添加11个元素;它仍然有前11个所以现在有22个元素。
  4. 将所有values添加到列表中。第一个崩溃,因为它已经在列表中。
  5. 一种解决方案是在values.clear()循环的顶部添加while(!done)