3


I am currently modifying a complex class that has nodes pointing to themselves just like linked lists or graphs. I want it to be used in shared memory using boost::interprocess functions. Now I am looking for the way to redesign it such that it stays generic and involves least changes.

template< class T >  
class node {  
  public:  
    T data;  
    node* prev;  
    node* next;  
};

The redesign should make use of the boost::interprocess::allocator allocator in order to implicitly use the relative smart pointers of type boost::interprocess::offset_ptr. I thought it should involve a second template parameter like

template< class T, class alloc_type = std::allocator< node< T > > >  
class node {
  public:  
    T data;  
    typename alloc_type::pointer prev;  
    typename alloc_type::pointer next;  
};

which of course doesn't work due to cyclic dependencies just as with references.
I hope a can get some help from a C++ class template pro on the best way to implement it. I had a look at the boost shared memory enabled containers but they are solving it in a rather complicated manner that involves several external classes.

Joh

AstroCB
  • 12,337
  • 20
  • 57
  • 73
Joh
  • 41
  • 2
  • That looks suspiciously like a node class in a doubly linked list. Is this because you simplify the example code that far, or is this indeed what that class looks like? If the latter, why not use `std::list` and pass a custom-allocator? – sbi Apr 07 '11 at 16:27
  • It is because of simplification, it is in fact a complex tree class. BTW: with std::list implementations do not seem to guarantee that they will use the allocator::pointer because the standard says that it is equivalent to a raw pointer. This is why boost::interprocess provides a set of standard containers. – Joh Apr 07 '11 at 16:33

2 Answers2

1

which of course doesn't work due to cyclic dependencies just as with references.

Yes, that will not work, because the type node is being defined and it's not yet complete, but you're passing it to allocator as type parameter. Hence the problem!

Also, node is a class template, but when you're passing it to allocator you're not providing type argument for node. But dont worry, even if you pass, it will not work since type node is not yet complete (as I said before).


Besides that you've another problem,

alloc_type::pointer prev;  
alloc_type::pointer next;  

Here you need typename as

typename alloc_type::pointer prev;  
typename alloc_type::pointer next;  
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    And... `std::allocator< node >` as `alloc_type`? – André Caron Apr 07 '11 at 16:18
  • Yep, sorry for the missing typenames and the T, I was minimizing the code it to show the basic problem: it is a cyclic dependency of class templates. – Joh Apr 07 '11 at 16:29
  • Yes, thank you. I am looking for a strategy to resolve this mutual dependency and hoped that someone had something in mind. – Joh Apr 07 '11 at 16:36
0

It seems to me that the allocator class belongs to the container, not the element. I realize that, for intrusive containers like yours, they can be the same. But, can we factor it back out?

How about:

#include <memory>

template <class T, class alloc_type >
struct nodePtr {
    typedef typename alloc_type::pointer pointer;
    typedef alloc_type allocator;
};


template< class T >
class node {
  public:
    typedef nodePtr<node<T>, std::allocator<node<T> > > pointer;
    // OR: typedef nodePtr<node<T>, my_allocator<node<T> > > pointer;
    T data;
    pointer prev;
    pointer next;
};

node<int> n;

Of course, I can't figure out how to pass std::allocator<> to node<>, but maybe you don't need that. Do you mind specifying your allocator's name in the middle of class node?

Or maybe, we could make your allocator the default allocator for nodePtr?

// untested
template <class T> class node;
template <class T, class alloc_type = my_allocator<node<T> > >
class nodePtr { /* ... */ };
template <class T> class node {
    public: typename nodePtr<T> prev;
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • Thanks for your suggestion, Rob. The problem is that the nodes are wrapped in a container class that will receive the allocator via the constructor. This is like it is done in boost and necessary, if the allocator is not stateless. However, I think I can pass a void allocator that can be converted into any type allocator. So I need to build a linked node data structure within this container class in a generic way. – Joh Apr 08 '11 at 08:48