Boost logo

Boost Users :

From: Andre Krause (post_at_[hidden])
Date: 2006-09-02 06:06:20


dear boost users, boost offers in lib pool the class object_pool.
as is stated in the docs, it allows for allocation with O(1) but
deallocation need O(n) time. i suppose it has to search the internal
list for the position of the object ro be freed.

but this could be speed up a lot by using a stack of free objects. if
one would like to allocate an object, a pointer to a free memory cell is
popped from the stack, if the object should be returned / freed to the
pool, that objects pointer is pushed onto the stack.

of course this causes memory overhead, but, for example if one would
like to implement a really large pool of small objects for a particle
system, then O(n) deallocation is prohibitive.

so my question is why boost does not offer an alternative version of
object_pool with both O(1) alloc and dealloc ?

below is my version of a stack based object pool with O(1) both alloc
and dealloc. i really do not like my implementation, but i did not know
how to do better...

template<class T> class Smallobjects_Pool
{
protected:
        class Node // a node of a double linked list
        {
        public:
                Node() {prev=next=NULL; idx=-1; }
                Node* prev;
                Node* next;
                int idx; // index to the objects - vector
                T obj;
        };
        //Node* next(int cur) { return objects[cur].next;}
        //Node* root() { return _root; }
        //Node* last() { return _last; }
protected:
        Node* _root;
        Node* _last;
        vector<Node> objects;
        vector<int> free_objects;
public:
        T & operator[](int i){return objects[i].obj;}
        bool empty() { return _root == NULL;}
        Smallobjects_Pool(int initial_size)
        {
                _root=NULL;
                _last=NULL;
                objects.resize(initial_size);
                free_objects.reserve(initial_size);
                for(unsigned int a=0;a<objects.size();a++)
                        free_objects.push_back(a);
        }
        void push_back(const T& t)
        {
                //assert(!free_objects.empty() && "out of capacity");
                if(free_objects.empty())
                {
                        PR("small object pool full..");
                        PR(objects.size() - free_objects.size());
                        return;
                }

                Node* new_obj = &(objects[free_objects.back()]);
                new_obj->idx = free_objects.back();
                free_objects.pop_back();

                if(_root==NULL)
                {
                        _root=new_obj;
                        new_obj->prev=NULL;
                        new_obj->next=NULL;
                }
                else
                {
                        _last->next=new_obj;
                        new_obj->prev=_last;
                        new_obj->next=NULL;
                }

                _last=new_obj;

                new_obj->obj = t;
        }

        
        class iterator
        {
        //protected:
        public:
                Node* i;
        public:
                iterator(Node* _i) : i(_i) {}
                ~iterator() {}
                iterator& operator=(const iterator& other) { i = other.i;
return(*this); } // The assignment and relational operators are
straightforward
                bool operator==(const iterator& it) { return(i == it.i); }
                bool operator!=(const iterator& it) { return(i != it.i); }

                iterator& operator++() { assert(i && "increment on null pointer"); i =
i->next; return(*this); } // Update my state such that I refer to the
next element in the SQueue.
                //Iterator& operator++(int) { Iterator tmp(*this); ++(*this);
return(tmp);}
                T& operator*() { return i->obj; } // Return a reference to the
value in the node. I do this instead of returning by value so a caller
can update the value in the node directly.
                T* operator->() { return &(i->obj); } // Return the address of the
value referred to.
        };

        iterator begin() { return(iterator(_root));}
        iterator end() { return(iterator( NULL));}
        iterator erase(iterator i)
        {

                assert(i.i!=NULL && "cannot free null pointer.");

                free_objects.push_back(i.i->idx);

                if(i.i == _last)
                {
                        if(i.i->prev != NULL)
                                _last = i.i->prev;
                        _last->next=NULL;
                        return NULL;
                }

                if(i.i == _root)
                {
                        _root = i.i->next;
                        _root->prev=NULL;
                        return _root;
                }

                i.i->prev->next = i.i->next;
                i.i->next->prev = i.i->prev;
                return iterator(i.i->next);
        }

};


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net