Hi Gavin, Il giorno ven 22 mar 2019 alle ore 05:44 Gavin Lambert via Boost-users < boost-users@lists.boost.org> ha scritto:
Did you look at std::make_shared<T>? It avoids the double allocation for the control block that you're complaining about. (Although you couldn't use it to allocate an arena block in this case -- while it does support array allocation, there is then only one control block for the whole array.)
Yes I know about std::make_shared<> and indeed I was using that solution before implementing the memory pool based on intrusive pointers. The problem is that in my workload I have several threads that need to get a smart pointer to a fairly-big object every time they process input data and they will release it later. Now allocating with std::make_shared<> a new object on every input data was causing my threads to do lots of mallocs/sec and that became the performace limiting factor. The use of a memory pool instead allows me to do a very large memory allocation from time to time (in blocks of e.g. 1024 items) and still have each single item of the memory pool independently refcounted. This usage pattern is not possible with std::shared_ptr<> and that's why I switched to boost::intrusive_ptr<> instead.
Also the use of default construction and explicit recycle methods (and requiring boost_intrusive_pool_item as a base class) is ugly.
You should be able to instead keep your pool_item type internal (not exposed to the consumer) and use aligned_storage to hold uninitialised storage for the actual item data, calling T's constructor and destructor as needed to allocate and recycle the slot.
My first implementation of the memory pool indeed was using C++11 perfect forwarding to call the ctor/dtor of type T when the item was pulled out the pool or was returning to it. I later removed such feature because I realized that calling the ctor of the items to recycle produced issues with classes having multiple inheritance IIRC. I don't think it's safe and sane to call the ctor of the same instance multiple times... I know that the implementation may be possibly refined from a C++/template style point of view but regarding performances I verified that it satifies well my needs and allows to write code using smart pointers that has zero-malloc when the memory pool has expanded to contain enough elements to handle the worst-simultaneous-active items... (Or just wrap it in
std/boost::optional, although that can introduce some nesting ambiguities.)
This is not very clear to me... but I will take a look at std::optional. Thanks for the suggestions though! Francesco