
2010/2/18 Ryan McConnehey <mccorywork@gmail.com>
I like your concept for deallocating the object that pool handed out. I am using a private static class within pool to provide the function to the shared_ptr destructor. This allowed the object to be delete if the pool was destroyed but causes a bottleneck for other pools of the same type.
As I understand your case is multiple buffers used in async operations in boost::asio. First: to gain performance, you need some reusable objects pool mechanics to avoid constant allocation/deallocation of memory used by buffers. Second: buffers must survive pool destruction while being used. Am I correct?
I have two questions. One, shouldn't the PoolObjectDeleter should be a template class?
To template or not is totally up to you :) Do you need some generic reusable code(could take some time to develop) or you need fast feature implementation and move further?
Two, why is the PoolObjectDeleter passed a shared_ptr<void>? It seems the pool_mem is to help with reference counting to determine if the pool is destroyed. Yet, I thought the enable_shared_from_this took care of the reference counting with the pool.lock().
In my sample pool_mem is malloc'ed objects data bodies memory, it would cause undefined behavior if accessed after "free". To avoid that shared_ptr is passed to PoolObjectDeleter. To determine if the pool is destroyed weak_ptr<Pool> is used. If I'm correct about your case I'd like to post some more code: typedef shared_ptr<asio::buffer> buffer_ptr; class PoolBufferDeleter { private: weak_ptr<Pool> pool; public: PoolBufferDeleter(const shared_ptr<Pool> &p) : pool(p) {} void operator()(asio::buffer *buf) { shared_ptr<Pool> shared_pool = this->pool.lock(); if(shared_pool) shared_pool->deallocate(buf); else { free(asio::buffer_cast<void*>(*buf)); delete buf; } } }; class Pool : enable_shared_from_this<Pool> { private: list<buffer_ptr> buffers; // free to use buffers public: buffer_ptr allocate(size_t sz) { // minimal size to use for(list<buffer_ptr>::iterator i = this->buffers.begin(); i!= this->buffers.end(); ++i) if(asio::buffer_size(*i) >= sz) { buffer_ptr ret_value = *i; this->buffers.erase(i); return ret_value; } // malloc is NOT checked!! return buffer_ptr(new asio::buffer(malloc(sz), sz), // T *t PoolBufferDeleter(shared_from_this())); // D d } void deallocate(asio::buffer *b) { this->buffers.push_front(buffer_ptr(b)); } }; Deleter holds a weak_ptr to pool, so it can determine pool state. It's alive - pass buffer to it, destroy otherwise.