So, I created a memory_pools container memory_pools based on the boost pool:
memory_pools.hpp
#ifndef MEMORY_POOL_HPP # define MEMORY_POOLS_HPP // boost # include <boost/pool/pool.hpp> # include <boost/unordered_map.hpp> template<typename ElementType> class memory_pools { public: template <typename> friend class memory_pools; private: using pool = boost::pool<>; public: using value_type = ElementType; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; using size_type = pool::size_type; using difference_type = pool::difference_type; public: template<typename OtherElementType> struct rebind { using other = memory_pools<OtherElementType>; }; public: memory_pools(); template<typename SourceElement> memory_pools(const memory_pools<SourceElement>&); public: pointer allocate(const size_type n); void deallocate(const pointer ptr, const size_type n); template<typename... Args> void construct(pointer, Args...); void destroy(pointer); public: bool operator==(const memory_pools&); bool operator!=(const memory_pools&); private: using pools_map = boost::unordered_map<std::size_t, std::shared_ptr<pool>>; private: std::shared_ptr<pools_map> pools_map_; std::shared_ptr<pool> pool_; }; # include <memory_pools.ipp> #endif
memory_pools.ipp
#ifndef MEMORY_POOLS_IPP # define MEMORY_POOLS_IPP template<typename ElementType> memory_pools<ElementType>::memory_pools() : pools_map_(std::make_shared<pools_map> (pools_map { std::make_pair (sizeof(ElementType), make_shared<pool>(sizeof(ElementType))) })), pool_(pools_map_->at(sizeof(ElementType))) { } template<typename ElementType> template<typename SourceElement> memory_pools<ElementType>::memory_pools (const memory_pools<SourceElement>& rebinded_from) : pools_map_(rebinded_from.pools_map_), pool_(pools_map_->insert (std::make_pair(sizeof(ElementType), make_shared<pool>(sizeof(ElementType)))).first->second) { } template<typename ElementType> typename memory_pools<ElementType>::pointer memory_pools<ElementType>::allocate (const size_type n) { pointer ret = static_cast<pointer>(pool_->ordered_malloc(n)); if ((!ret) && n) throw std::bad_alloc(); return (ret); } template<typename ElementType> void memory_pools<ElementType>::deallocate (const pointer ptr, const size_type n) { pool_->ordered_free(ptr, n); } template<typename ElementType> template<typename... Args> void memory_pools<ElementType>::construct(pointer ptr, Args... args) { new (ptr) ElementType(std::forward<Args>(args)...); } template<typename ElementType> void memory_pools<ElementType>::destroy(pointer ptr) { ptr->~ElementType(); } template<typename ElementType> bool memory_pools<ElementType>::operator==(const memory_pools& rhs) { return (pools_map_ == rhs.pools_map_); } template<typename ElementType> bool memory_pools<ElementType>::operator!=(const memory_pools& rhs) { return (pools_map_ != rhs.pools_map_); } #endif
Then when I test it using:
#include <memory_pools.hpp> int main(void) { using pools_type = memory_pools<std::pair<const int, int>>; pools_type pools; boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>, pools_type> map; //boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>> map; for (unsigned int i = 0; i < 20000; ++i) { map[i] = i + 1; } return (0); }
From clang3.5 on macOSX 10.10 I got:
$ time ./a.out real 0m1.873s user 0m1.850s sys 0m0.009s
If I run:
#include <memory_pools.hpp> int main(void) { using pools_type = memory_pools<std::pair<const int, int>>; pools_type pools; //boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>, pools_type> map; boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>> map; for (unsigned int i = 0; i < 20000; ++i) { map[i] = i + 1; } return (0); }
I have:
$ time ./a.out real 0m0.019s user 0m0.016s sys 0m0.002s
Question
Is memory allocation using the boost pool supposedly slow, or is my test invalid for some reason?
EDIT
After Carmeron's comment, I added the -O3 and -DNDEBUG , now I have:
$time ./a.out real 0m0.438s user 0m0.431s sys 0m0.003s
for version memory_pools and:
$ time ./a.out real 0m0.008s user 0m0.006s sys 0m0.002s
for the standard version of the distributor.
Question
The question still remains, is it normal slower?