Using smart pointers with Boost.Intrusive containers

| Home | Libraries | People | FAQ | More

## Using smart pointers with Boost.Intrusive containers

Boost.Intrusive hooks can be configured to use other pointers than raw pointers. When a Boost.Intrusive hook is configured with an smart pointer as an argument, this pointer configuration is passed to the containers. For example, if the following hook is configured with an smart pointer (for example, an offset pointer from Boost.Interprocess):

    #include <boost/intrusive/list.hpp>
    #include <boost/interprocess/offset_ptr.hpp>

    using namespace boost::intrusive;
    namespace ip = boost::interprocess;

    class shared_memory_data
       //Declare the hook with an offset_ptr from Boost.Interprocess
       //to make this class compatible with shared memory
       :  public list_base_hook< void_pointer< ip::offset_ptr<void> > >
    {
       int data_id_;
       public:

       int get() const   {  return data_id_;  }
       void set(int id)  {  data_id_ = id;    }
    };

Any intrusive list constructed using this hook will be ready for shared memory, because the intrusive list will also use offset pointers internally. For example, we can create an intrusive list in shared memory combining Boost.Interprocess and Boost.Intrusive:

    #include <boost/interprocess/managed_shared_memory.hpp>
    #include <boost/interprocess/containers/vector.hpp>
    #include <boost/interprocess/containers/list.hpp>
    #include <boost/interprocess/allocators/allocator.hpp>

    //Definition of the shared memory friendly intrusive list
    typedef ip::list<shared_memory_data> shm_list_t;

    int main()
    {
       //Now create an intrusive list in shared memory:
       //nodes and the container itself must be created in shared memory
       const int MaxElem    = 100;
       const int ShmSize    = 50000;
       const char *ShmName  = get_shared_memory_name();
       {
          //Erase all old shared memory
          ip::shared_memory_object::remove(ShmName);
          ip::managed_shared_memory shm(ip::create_only, ShmName, ShmSize);

          //Create all nodes in shared memory using a shared memory vector
          //See Boost.Interprocess documentation for more information on this
          typedef ip::allocator
             < shared_memory_data, ip::managed_shared_memory::segment_manager>
                shm_allocator_t;
          typedef ip::vector<shared_memory_data, shm_allocator_t> shm_vector_t;
          shm_allocator_t shm_alloc(shm.get_segment_manager());
          shm_vector_t *pshm_vect =
             shm.construct<shm_vector_t>(ip::anonymous_instance)(shm_alloc);
          pshm_vect->resize(MaxElem);

          //Initialize all the nodes
          for(int i = 0; i < MaxElem; ++i)    (*pshm_vect)[i].set(i);

          //Now create the shared memory intrusive list
          shm_list_t *plist = shm.construct<shm_list_t>(ip::anonymous_instance)();
          plist->insert(plist->end(), pshm_vect->begin(), pshm_vect->end());

          //Check all the inserted nodes
          int checker = 0;
          for( shm_list_t::const_iterator it = plist->begin(), itend(plist->end())
             ; it != itend; ++it, ++checker){
             if(it->get() != checker)   return false;
          }

          //Now delete the list and after that, the nodes
          shm.destroy_ptr(plist);
          shm.destroy_ptr(pshm_vect);
       }
       ip::shared_memory_object::remove(ShmName);
       return 0;
    }

### Requirements for smart pointers compatible with Boost.Intrusive

Not every smart pointer is compatible with Boost.Intrusive, the smart pointer must have the following features:

- It must support the same operations as a raw pointer, except casting.
- It must be convertible to a raw pointer and constructible from a raw pointer.
- It must have the same ownership semantics as a raw pointer. This means that resource management smart pointers (like `boost::shared_ptr`) can't be used.

The conversion from the smart pointer to a raw pointer must be implemented following Boost smart pointer `detail::get_pointer()` function. This function will be found using ADL. For example, for `boost::interprocess::offset_ptr` `detail::get_pointer` is defined as follows:

    template<class T>
    T * detail::get_pointer(boost::interprocess::offset_ptr<T> const & p)
    {  return p.get();   }