|
Boost Users : |
Subject: Re: [Boost-users] (Newbie) Embedded programming, memory pools, and allocate_shared()
From: Steven Boswell II (ulatekh_at_[hidden])
Date: 2017-12-08 19:18:58
So far, the answer seems to involve referring to boost implementation details, which doesn't thrill me.I just wanted to create some memory-pools that could be used to allocate objects referred to through boost:shared_ptr<>.I want to avoid non-pool memory-allocation, and for each shared-object allocation to involve one (and only one) allocation from one pool, i.e. to be as predictable and compact as possible.
This hand-written definition for a pool and an allocator seem to do what I want:
----------
template<typename T>
class my_pool
{
private:
 char *rawStorage;
 T *storage;
 T *nextFree;
public:
 my_pool(size_t S)
   : storage(nullptr), nextFree(nullptr)
 {
   // Allocate memory.
   rawStorage = new char[sizeof(T) * S];
   storage = reinterpret_cast<T*>( rawStorage );
   // All objects are free, initially.
   for (size_t i = 0; i < S; ++i)
   {
     T **pFreeObject = reinterpret_cast<T**>(&storage[i]);
     *pFreeObject = nextFree;
     nextFree = reinterpret_cast<T*>(&storage[i]);
   }
 }
 ~my_pool()
 {
   // TODO: Verify that all allocated objects have been freed.
   delete[] rawStorage;
 }
 T *allocate()
 {
   T *freeObject = nextFree;
   if (nextFree != nullptr)
   {
     T **pFreeObject = reinterpret_cast<T**>(nextFree);
     nextFree = *pFreeObject;
   }
   return freeObject;
 }
 void deallocate(T *obj)
 {
   T **pFreeObject = reinterpret_cast<T**>(obj);
   *pFreeObject = nextFree;
   nextFree = obj;
 }
};
template<typename T>
class my_allocator : public at_boost::detail::sp_ms_deleter<T>
{
public:
 typedef at_boost::detail::sp_counted_impl_pda<T *, at_boost::detail::sp_ms_deleter<T>, my_allocator<T> > shared_type;
 typedef my_pool<shared_type> pool_type;
private:
 pool_type &m_rPool;
 void operator=(my_allocator const &other); // Disallow assignment.
public:
 explicit my_allocator(pool_type &a_rPool) : m_rPool(a_rPool) { }
 my_allocator(my_allocator const &other) : m_rPool(other.m_rPool) { }
 template <typename U>
 struct rebind
 {
   typedef my_allocator/*<U>*/ other;
 };
 shared_type *allocate(int iCount)
 {
   if (iCount == 1) // Only expected to allocate single objects.
     return m_rPool.allocate();
   return nullptr;
 }
 void deallocate(shared_type *obj, size_t iCount)
 {
   m_rPool.deallocate(obj);
 }
};
----------
It still needs polish, but it's just a proof of concept.
Here's some code that uses the pool/allocator:
----------
my_allocator<int>::pool_type myPool (1024);
my_allocator<int> myAllocator(myPool);
boost::shared_ptr<int> pTest = boost::allocate_shared<int, my_allocator<int> >(myAllocator);
int iVal0 = *pTest;
*pTest = sizeof(my_allocator<int>::shared_type);
int iVal1 = *pTest;
----------
No big deal. Mostly, the test is to make sure that ::operator new() doesn't get called after the construction of the pool, and that seems to be true.
I'm surprised that my expected usage of memory-pools isn't more common.Maybe using boost in an environment with constraints on dynamic memory allocation is unusual?
Also, at some point, I need to figure out why my definition of my_allocator<T>::rebind can't use <U> in the way that the standard boost allocators do.I get an incomprehensible error-message when I do that:
----------
boost\smart_ptr\detail\sp_counted_impl.hpp(237): error C2664: 'my_allocator<T>::my_allocator(my_pool<at_boost::detail::sp_counted_impl_pda<P,D,A>> &)' : cannot convert parameter 1 from 'my_allocator<T>' to 'my_pool<T> &'----------
Any comments on what I'm trying to do here?
-Steven
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