I would like to take advantage of the following advertised feature of boost::fast_pool_allocator
(see the Boost documentation for Boost Pool):
The answer to this question is contained in the comments beneath @qehgt's answer, and in detail in this new question.
Namely:
There is a clear and formal distinction between two related aspects of object instantiation and deletion:
(1) Allocation and deallocation of memory
(2) Calling of constructors and destructors
The purpose of a custom allocator is (1) only.
The container objects handle (2), and they call functions in the custom allocator to determine the location of memory in which to construct the object, and to tell the custom allocator that it's OK to free the allocated memory for given objects. But the calls to the constructor/destructor themselves are made by the container, not by the custom allocator.
Therefore, the way to achieve the goal of this question is the following: Declare the container object via new
and NEVER CALL delete
on it (but use the custom allocator to guarantee that the objects you later create in the container are stored in the memory pool, and then manually free the memory pool yourself by calling purge_memory()
):
class Obj { // has operator<() for use with std::set };
typedef std::set<Obj, std::less<Obj>, boost::fast_pool_allocator<Obj>> fast_set_obj;
// Deliberately do not use a managed pointer -
// I will *NOT* delete this object, but instead
// I will manage the memory using the memory pool!!!
fast_set_obj * mset = new fast_set_obj;
// ... add some Obj's to 'mset'
mset->insert(Obj());
mset->insert(Obj());
// Do something desireable with the set ...
...
// All done.
// It's time to release the memory, but do NOT call any Obj destructors.
// The following line of code works exactly as intended.
boost::singleton_pool<boost::fast_pool_allocator_tag, sizeof(Obj const)>::purge_memory();
(The above code is taken from the linked question, above.)
However, I am still having an issue, not directly related to the intention behind this current question: The code above does not work if a map
is used instead of a set
. See the linked question for details.
You pass the custom allocator into your std::map
class. So, this allocator will be used for everything inside of std::map
: for all Obj
data and also for nodes of a binary tree of std::map
. As the result, if you call purge_memory()
in Foo
's destructor then all this memory becomes invalid, and it crashes in std::map
destructor.
Your assumption that a custom allocator is responsible for objects' de-allocation is not correct: it's a std::map
's task to free all objects. So, ~Obj()
will be called regardless if you pass the custom allocator or if you use a default one.
I don't see any elegant solution for your question. But this approach should work:
placement new
to create Foo
object from pool's memory,Foo
object as usual,purge_memory()
to release all memory from the pool. No destructors ~Obj
or ~std::map
will be called.By default pool uses the default_user_allocator_new_delete
allocator. This will destroy underlying objects by calling the destructor first and then reclaiming underlying memory. The default_user_allocator_malloc_free
will cause malloc'ed memory to be reclaimed without firing the destructor - hence drop[ing] them off into oblivion
.
That said, if your tree is really that complicated, using free instead of firing destructors seems like a really good way to start chopping branches out from under yourself and potentially start leaking memory you can no longer reach.