/*
The pool allocator is not being used properly, somehow, with std::list.
When you go to purge the pool, it says nothing was purged, because nothing is even registered as being allocated in the pool.
What is going on here?
I have included copious debugging information. I've even provided a dummy modification of the boost::pool_allocator class to show what's going on.
It's weird. If you change l_type to an std::vector, everything will work, and the output will be: purged? 1
This program outputs the following when l_type is std::list,
debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::debug_pool_allocator() [with Tag = foo_tag, T = int, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::debug_pool_allocator(const debug_pool_allocator<Tag, U, UserAllocator, Mutex, NextSize>&) [with U = int, Tag = foo_tag, T = std::_List_node<int>, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
static T* debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::allocate(typename boost::pool<UserAllocator>::size_type) [with Tag = foo_tag, T = std::_List_node<int>, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
---
static T* debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::allocate(typename boost::pool<UserAllocator>::size_type) [with Tag = foo_tag, T = std::_List_node<int>, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
---
...
purged? 0
released? 0
This program outputs the following when l_type is std::vector,
debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::debug_pool_allocator() [with Tag = foo_tag, T = int, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
static T* debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::allocate(typename boost::pool<UserAllocator>::size_type) [with Tag = foo_tag, T = int, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
---
static T* debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::allocate(typename boost::pool<UserAllocator>::size_type) [with Tag = foo_tag, T = int, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
static void debug_pool_allocator<Tag, T, UserAllocator, Mutex, NextSize>::deallocate(T*, typename boost::pool<UserAllocator>::size_type) [with Tag = foo_tag, T = int, UserAllocator = boost::default_user_allocator_new_delete, Mutex = boost::details::pool::default_mutex, unsigned int NextSize = 32u]
---
...
purged? 1
released? 0
*/
#include <iostream>
using std::cout;
using std::endl;
#include <list>
#include <vector>
#include <boost/current_function.hpp>
#include <boost/limits.hpp>
// std::numeric_limits
#include <new>
// std::bad_alloc
#include <boost/pool/poolfwd.hpp>
#include <boost/pool/singleton_pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#define DEBUG_FUNC cout << BOOST_CURRENT_FUNCTION << " " << endl
template <
class Tag,
class T,
class UserAllocator = boost::default_user_allocator_new_delete,
class Mutex = boost::details::pool::default_mutex,
unsigned NextSize = 32
>
class debug_pool_allocator
{
public:
typedef T value_type;
typedef UserAllocator user_allocator;
typedef Mutex mutex;
static unsigned const next_size = NextSize;
typedef value_type* pointer;
typedef value_type const* const_pointer;
typedef value_type& reference;
typedef value_type const& const_reference;
typedef typename boost::pool<UserAllocator>::size_type size_type;
typedef typename boost::pool<UserAllocator>::difference_type difference_type;
template <class U>
struct rebind {
typedef debug_pool_allocator<Tag, U, UserAllocator, Mutex, NextSize> other;
};
debug_pool_allocator() {
DEBUG_FUNC;
}
// default copy constructor
// default assignment operator
// not explicit, mimicking std::allocator [20.4.1]
template <class U>
debug_pool_allocator(
debug_pool_allocator<Tag, U, UserAllocator, Mutex, NextSize> const&
) {
DEBUG_FUNC;
}
// default destructor
static pointer address(reference r) {
DEBUG_FUNC;
return &r;
}
static const_pointer address(const_reference s) {
DEBUG_FUNC;
return &s;
}
static size_type max_size() {
DEBUG_FUNC;
return (std::numeric_limits<size_type>::max)();
}
static void construct(pointer const ptr, value_type const& t) {
DEBUG_FUNC;
new(ptr) T(t);
}
static void destroy(pointer const ptr) {
DEBUG_FUNC;
ptr->~T();
}
bool operator==(debug_pool_allocator const&) const {
DEBUG_FUNC;
return true;
}
bool operator!=(debug_pool_allocator const&) const {
DEBUG_FUNC;
return false;
}
static pointer allocate(size_type const n) {
DEBUG_FUNC;
const pointer ret =
static_cast<pointer>(
boost::singleton_pool<
Tag, sizeof(T), UserAllocator, Mutex, NextSize
>::ordered_malloc(n)
)
;
if (ret == 0)
throw std::bad_alloc();
return ret;
}
static pointer allocate(size_type const n, void const* const) {
DEBUG_FUNC;
return allocate(n);
}
static void deallocate(pointer const ptr, size_type const n) {
DEBUG_FUNC;
boost::singleton_pool<
Tag, sizeof(T), UserAllocator, Mutex, NextSize
>::ordered_free(ptr, n);
}
};
// ---
struct foo_tag {};
// IF YOU CHANGE THIS TO std::vector, IT WILL DEALLOCATE PROPERLY!
typedef std::list<
int,
debug_pool_allocator<foo_tag, int>
> l_type;
int main()
{
bool success = false;
l_type* l = new l_type;
for (int i=0; i<2; ++i) {
l->push_back(444);
cout << "---" << endl;
}
cout << "..." << endl;
success = boost::singleton_pool<foo_tag, sizeof(int)>::purge_memory();
cout << "purged? " << success << endl;
success = boost::singleton_pool<foo_tag, sizeof(int)>::release_memory();
cout << "released? " << success << endl;
}