Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost Pool experience requested. Is it useful as allocator with preallocation?

Recently i have been looking for a pool/allocator mechanism. Boost Pool seems to provide the solution, but there is still things, which it have not been able to deduce from the documentation.

What need to be allocated

  1. Several small classes (~30 chars)
  2. std::map (i want to ensure it do not perform dynamic allocator by itself)
  3. allocation within pugi::xml
  4. std::strings

How to control of address space for allocation (or just amount)

The object_pool seem the to provide a good way for allocating need 1) However it would like to set a fixed size for the allocator to use. By default it grabs memory be ifself. If possible i would like to give it the address space it can play within.

char * mem_for_class[1024*1024];
boost::object_pool<my_class,mem_for_class> q;

or:

const int max_no_objs=1024;
boost::object_pool<my_class,max_no_objs> q;

Although the UserAllocator is available in Boost::Pool; it seem to defeat the point. I am afraid the control needed would make it too inefficient... and it would be better to start from scratch.

It it possible to set a fixed area for pool_allocator ?

The question is a bit similar to the first. Do boost pool provide any way of limiting how much / where there is allocated memory when giving boost::pool_allocator to a std-type-class (e.g. map)

My scenario

Embedded linux programming. The system must keep running for..ever. So we can not risk any memory segmentation. Currently i mostly either static allocation (stack), but also a few raw "new"s. I would like an allocation scheme that ensure i use the same memory area each time the program loops. Speed /space is important, but safety is still top priority.

I hope StackOverflow is the place to ask. I tried contacting the author of Boost::Pool "Stephen" without luck. I have not found any Boost-specific forum.

like image 610
Steffen Villadsen Avatar asked Feb 16 '14 14:02

Steffen Villadsen


People also ask

What is pool allocator?

A Pool allocator (or simply, a Memory pool) is a variation of the fast Bump-allocator, which in general allows O(1) allocation, when a free block is found right away, without searching a free-list. To achieve this fast allocation, usually a pool allocator uses blocks of a predefined size.

Is boost :: pool thread safe?

The pool allocators are thread safe, pool as such is not.


1 Answers

You can always create an allocator that works with STL. If it works with STL, it should work with boost as you are able to pass boost allocators to STL containers..

Considering the above, an allocator that can allocate at a specified memory address AND has a size limitation specified by you can be written as follows:

#include <iostream>
#include <vector>

template<typename T>
class CAllocator
{
    private:
        std::size_t size;
        T* data = nullptr;

    public:
        typedef T* pointer;
        typedef const T* const_pointer;

        typedef T& reference;
        typedef const T& const_reference;

        typedef std::size_t size_type;
        typedef std::ptrdiff_t difference_type;

        typedef T value_type;


        CAllocator() {}
        CAllocator(pointer data_ptr, size_type max_size) noexcept : size(max_size), data(data_ptr) {};

        template<typename U>
        CAllocator(const CAllocator<U>& other) noexcept {};

        CAllocator(const CAllocator &other) : size(other.size), data(other.data) {}

        template<typename U>
        struct rebind {typedef CAllocator<U> other;};

        pointer allocate(size_type n, const void* hint = 0) {return &data[0];}
        void deallocate(void* ptr, size_type n) {}
        size_type max_size() const {return size;}
};

template <typename T, typename U>
inline bool operator == (const CAllocator<T>&, const CAllocator<U>&) {return true;}

template <typename T, typename U>
inline bool operator != (const CAllocator<T>& a, const CAllocator<U>& b) {return !(a == b);}





int main()
{
    const int size = 1024 / 4;
    int ptr[size];
    std::vector<int, CAllocator<int>> vec(CAllocator<int>(&ptr[0], size));

    int ptr2[size];
    std::vector<int, CAllocator<int>> vec2(CAllocator<int>(&ptr2[0], size));

    vec.push_back(10);
    vec.push_back(20);
    vec2.push_back(30);
    vec2.push_back(40);


    for (std::size_t i = 0; i < vec2.size(); ++i)
    {
        int* val = &ptr2[i];
        std::cout<<*val<<"\n";
    }

    std::cout<<"\n\n";

    vec2 = vec;

    for (std::size_t i = 0; i < vec2.size(); ++i)
    {
        int* val = &ptr2[i];
        std::cout<<*val<<"\n";
    }

    std::cout<<"\n\n";
    vec2.clear();

    vec2.push_back(100);
    vec2.push_back(200);

    for (std::size_t i = 0; i < vec2.size(); ++i)
    {
        int* val = &ptr2[i];
        std::cout<<*val<<"\n";
    }
}

This allocator makes sure that all memory is allocated at a specified address. No more than the amount you specify can be allocated with the freedom to allocate were you want whether it is on the stack or the heap.

You may create your own pool or use a std::unique_ptr as the pool for a single container.

EDIT: For strings, you need an offset of sizeof(_Rep_base). See: Why std::string allocating twice?

and http://ideone.com/QWtxWg

It is defined as:

struct _Rep_base
{
    std::size_t     _M_length;
    std::size_t     _M_capacity;
    _Atomic_word        _M_refcount;
};

So the example becomes:

struct Repbase
{
    std::size_t     length;
    std::size_t     capacity;
    std::int16_t    refcount;
};

int main()
{
    typedef std::basic_string<char, std::char_traits<char>, CAllocator<char>> CAString;

    const int size = 1024;
    char ptr[size] = {0};

    CAString str(CAllocator<char>(&ptr[0], size));
    str = "Hello";

    std::cout<<&ptr[sizeof(Repbase)];
}
like image 130
Brandon Avatar answered Sep 28 '22 03:09

Brandon