Trying to learn boost::intrusive Q2

后端 未结 2 407
故里飘歌
故里飘歌 2021-01-17 06:26

if I uncomment these

//BaseList   baselist; 
//MemberList memberlist;

outside the loop and comment out the ones inside the loop it

相关标签:
2条回答
  • 2021-01-17 07:04

    Here's the error message, which you omitted:

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

    From this we can understand that an element is being inserted twice. This isn't valid with intrusive containers in general.

    When you have your lists inside the loop, they are destroyed and recreated each time. But when they are outside, you never clear them, and you also never clear values, so this sequence occurs:

    1. Add 11 elements to values.
    2. Add all values to the lists.
    3. Add 11 elements to values; it still has the previous 11 so now 22 elements.
    4. Add all values to the lists. Crash on the first one, because it is already in a list.

    One solution is to add values.clear() at the top of the while(!done) loop.

    0 讨论(0)
  • 2021-01-17 07:15

    I've seen it late, but anyways, here goes:

    1. What you describe matches exactly the implementation of an intrusive hash table of MyClass elements, where

      • anInt1 is the hash (the bucket identifier) for an element
      • the bucket lists are implemented as linked lists
      • equality is defined as equality of (anInt1, Name)

        enter image description here


      So really, your program could just be:

      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. if you really wanted contiguous storage, I can only assume you wanted this for performance

      • you do not want to use pointers instead of objects, since that simply negates the memory layout ("AllThingsBunchedTogether") benefits and you'd be better of with the unordered_set or unodered_map as above

      • you do not want to use auto_unlink mode, since it cripples performance (by doing uncontrolled deletion triggers, by inhibiting constant-time size() and by creating thread safety issues)

      • instead, you should employ the above stratagy, but with boost::intrusive::unordered_set instead see http://www.boost.org/doc/libs/1_57_0/doc/html/intrusive/unordered_set_unordered_multiset.html

        Here, again, is a proof-of-concept:

        Live On Coliru

        #include <vector>
        #include <iostream>
        #include <boost/intrusive/unordered_set.hpp>
        #include <vector>
        //#include <functional>
        //#include <algorithm>
        
        namespace bic = boost::intrusive;
        
        struct MyClass : bic::unordered_set_base_hook<bic::link_mode<bic::auto_unlink>>
        {
            std::string name;
            int anInt1;
            mutable bool bIsMarkedToDelete;
        
            MyClass(std::string name, int i) : name(name), anInt1(i), bIsMarkedToDelete(false) {}
        
            bool operator==(MyClass const& o) const { return anInt1 == o.anInt1 && name == o.name; }
        
            struct hasher { size_t operator()(MyClass const& o) const { return o.anInt1; } };
        };
        
        typedef bic::unordered_set<MyClass, bic::hash<MyClass::hasher>, bic::constant_time_size<false> > HashTable;
        
        int main() {
        
            std::vector<MyClass> values {
                MyClass { "John", 0 }, MyClass { "Mike",  1 }, MyClass { "Dagobart", 2 },
                MyClass { "John", 3 }, MyClass { "Mike",  4 }, MyClass { "Dagobart", 5 },
                MyClass { "John", 6 }, MyClass { "Mike",  7 }, MyClass { "Dagobart", 8 },
                MyClass { "John", 9 }, MyClass { "Mike", 10 },
            }; 
        
            HashTable::bucket_type buckets[100];
            HashTable hashtable(values.begin(), values.end(), HashTable::bucket_traits(buckets, 100)); 
        
            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);
        
                    values.erase(std::remove_if(begin(values), end(values), std::mem_fn(&MyClass::bIsMarkedToDelete)));
                }
        
                std::cout << "i=" << i << ", values.size():    " << values.size()    << "\n";
                std::cout << "i=" << i << ", hashtable.size(): " << hashtable.size() << "\n";
            }
            values.clear();
            std::cout << "Done\n";
        }
        
    0 讨论(0)
提交回复
热议问题