问题
I am new to boost and I want to know how exactly the boost::pool libraries can help me in creating a custom memory allocator. And I have two vector of struct objects. First vector is of structure type A, while second vector is of structure type B. How can I reuse the memory allocated to the first vector to the second vector.
回答1:
Boost Pool is a library that defines a few allocator types.
Obviously, the focus of the library is to provide Pool Allocators.
Pool Allocators shine when you allocate objects of identical size.
Note If your structure
Aand structureBaren't identical/very similar size you may not like this design assumption.
The allocators provided by the framework work with singleton pools, and they differentiate on the size of your container value_type. That's a bit inflexible if you want to reuse or even share the pool between different value-types. Also, singleton pools can be inflexible and imply thread-safety costs.
So, I wanted to see whether I could whip up the simplest allocator that alleviates some of these issues.
I used the source to boost::pool_alloc and the cppreference example as inspiration, and then did some testing and memory profiling.
A More Flexible Stateful Allocator
Here's the simplest pool allocator I could think of:
using Pool = boost::pool<boost::default_user_allocator_malloc_free>;
template <typename T> struct my_pool_alloc {
using value_type = T;
my_pool_alloc(Pool& pool) : _pool(pool) {
assert(pool_size() >= sizeof(T));
}
template <typename U>
my_pool_alloc(my_pool_alloc<U> const& other) : _pool(other._pool) {
assert(pool_size() >= sizeof(T));
}
T *allocate(const size_t n) {
T* ret = static_cast<T*>(_pool.ordered_malloc(n));
if (!ret && n) throw std::bad_alloc();
return ret;
}
void deallocate(T* ptr, const size_t n) {
if (ptr && n) _pool.ordered_free(ptr, n);
}
// for comparing
size_t pool_size() const { return _pool.get_requested_size(); }
private:
Pool& _pool;
};
template <class T, class U> bool operator==(const my_pool_alloc<T> &a, const my_pool_alloc<U> &b) { return a.pool_size()==b.pool_size(); }
template <class T, class U> bool operator!=(const my_pool_alloc<T> &a, const my_pool_alloc<U> &b) { return a.pool_size()!=b.pool_size(); }
Notes:
- This allocator is stateful, and thus requires container implementations that allow them (such as Boost Container, Boost MultiIndex). In theory, all C++11-compliant standard libraries should also support them
- The comparisons should guide the containers to swap/copy the allocator or not. This is not an area I've though much about and the chosen approach to mark all pools of different requested-sizes different might be inadequate for some.
Sample, Tests
On my compilers it works for both std::vector and Boost's vector:
- Live On Coliru - with GCC std::vector
- Live On Coliru - with GCC boost::container::vector
- Live On Coliru - with Clang std::vector
- Live On Coliru - with Clang boost::container::vector
All runs are leak-free and ubsan/asan clean.
Note how we re-use the same pool with different containers of different struct sizes, and how we can even use it with multiple live containers at a time, provided that the element types fit in the request size (32)
struct A { char data[7]; };
struct B { char data[29]; };
int main() {
//using boost::container::vector;
using std::vector;
Pool pool(32); // 32 should fit both sizeof(A) and sizeof(B)
{
vector<A, my_pool_alloc<A> > v(1024, pool);
v.resize(20480);
};
// pool.release_memory();
{
vector<B, my_pool_alloc<B> > v(1024, pool);
v.resize(20480);
}
// pool.release_memory();
// sharing the pool between multiple live containers
{
vector<A, my_pool_alloc<A> > v(512, pool);
vector<B, my_pool_alloc<B> > w(512, pool);
v.resize(10240);
w.resize(10240);
};
}
Profiling
Using Valgrind's Memory profiler shows, with the release_memory lines commented out as shown:
When commenting in the release_memory() calls:
I hope this looks like the thing you wanted.
Further Ideas: Simple Segregated Storage
This allocator uses the existing pool which delegate back to malloc/free to allocate memory on demand. To use it with a fixed "realm", you might prefer using simple_segregated_storage directly. This article looks like a good starter https://theboostcpplibraries.com/boost.pool
来源:https://stackoverflow.com/questions/48782450/how-to-use-boostpool-library-to-create-a-custom-memory-allocator