如何确定由'std :: map'创建的节点的大小?与' boost :: pool_allocator'一起使用(以跨平台的方式)?

时间:2014-04-09 01:51:10

标签: c++ memory-management c++11 boost pool

更新

根据评论,回答和其他研究,我得出的结论是,setmap在节点开销方面通常没有区别。接下来我的问题是:

  

如何确定节点开销以方便使用   boost::pool_allocator作为自定义分配器?

而且,进一步的更新:节点开销可能永远不会超过4个指针的大小,因此只需清除sizeof(T)的增强池,{{1} },sizeof(T)+sizeof(int)sizeof(T) + 2*sizeof(int)sizeof(T) + 3*sizeof(int)(或64位系统的sizeof(T) + 4*sizeof(int))应该没问题。这就是我实际做的事情,并且有效。


我希望通过避免调用这些对象的析构函数来使用boost memory pool来管理数千个微小的,大小相同的对象,而是在每个包含许多实例的单个行中释放内存。 / p>

我发布了关于此问题的another question,这个问题的答案让我明白我 需要回答的问题是我在这里要问的问题。

请考虑以下代码:

int64_t

如果您进入最后一行代码的class Obj { // ... has an operator<() ... }; 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(); 函数,您将看到purge_memory()很好地从系统中释放内存,正如所希望的那样。 (不会调用fast_pool_allocator个析构函数,因为如上面链接的问题所述,自定义分配器的工作是只是来分配和释放内存,到调用构造函数或析构函数。)

它可以根据需要精确地工作。太好了!

然而,这是问题所在。如果您将Obj替换为set,然后在map的调用中尝试使用boost::pool_allocator没有任何反应

purge_memory()

如上所述,最后一行代码什么都不做。原因是typedef std::map<int, int, std::less<int>, boost::fast_pool_allocator<std::pair<int const, int>>> fast_map_obj; // Ditto above: Deliberately do not use managed pointer mast_map_obj * mmap = new fast_map_obj; mmap[5] = Obj(); mmap[6] = Obj(); ... // Uh-oh. The following line of code DOES NOTHING, because I was using a map, not a set! boost::singleton_pool<boost::fast_pool_allocator_tag, sizeof(std::pair<int const, int>)>::purge_memory(); 是一个仅对对象of a given size that is fixed at compile-time作出响应并管理内存的单例。这就是调用boost::fast_pool_allocator的表达式中使用sizeof参数的原因 - 它告诉Boost Pool代码各种不同的单例内存要清除的池(假设由于先前已经实例化而存在所请求的池)。

不幸的是,因为选择要清除的内存池是依赖于大小的,所以 critical 管理内部对象的大小(即,通过调用自定义分配的内存中创建和销毁) allocator)是众所周知的。遗憾的是,对于purge_memory()std::map管理的内部对象的大小既不是map也不是sizeof(Obj)

我的问题是:您如何严格按照C ++ 11标准以跨平台方式确定sizeof(std::pair<int const, Obj>)内部管理的对象的大小,以便与{{1}一起使用}}?

这甚至可能吗?

2 个答案:

答案 0 :(得分:2)

问题在于您不知道set用于节点的内部类型。

虽然我还没弄清楚如何在编译时确定这一点,但您可以编写一个跟踪分配器,在调用sizeof时打印出allocate节点类型,如:

template<typename T>
struct SimpleAllocator : private std::allocator<T>
{
    using value_type = T;
    using pointer = typename std::allocator<T>::pointer;
    using size_type = typename std::allocator<T>::size_type;

    pointer allocate(size_type n)
    {   
        std::cout << "Allocator sizeof(T)==" << sizeof(T) << '\n';
        return std::allocator<T>::allocate(n);
    }   

    void deallocate(pointer p, size_type n)
    { return std::allocator<T>::deallocate(p, n); }
};

还有一个小测试程序(我正在测试一组整数):

std::set<int, std::less<int>, SimpleAllocator<int>> s;
s.insert(2);

在我的系统上,我输出:

  

分配器sizeof(T)== 32

答案 1 :(得分:2)

没有一种真正的跨平台方式可以推断出你所追求的是什么,因为每个地图实现都以自己的方式不满意,但通常它是将在池中分配的地图节点。

对于标准库的不同实现,这看起来有所不同,因此您需要为不同版本编写#ifdef - ed代码。有了脆弱性警告,这里是g ++ / clang ++ / msc编译器及其std libs的主要内容:

// libstdc++
boost::singleton_pool<boost::fast_pool_allocator_tag,
    sizeof(std::_Rb_tree_node<fast_map_obj::value_type>)>::purge_memory()

// libc++
boost::singleton_pool<boost::fast_pool_allocator_tag,
    sizeof(std::__tree_node<fast_map_obj::value_type, void*>)>::purge_memory()

// msvc 2013 (incl. nov ctp)
boost::singleton_pool<boost::fast_pool_allocator_tag,
    sizeof(fast_map_obj::_Node)>::purge_memory()

以下是一些有用的链接,用于查找必要的定义:

  

http://www.boost.org/doc/libs/1_55_0/boost/config/compiler/

     

http://sourceforge.net/p/predef/wiki/Compilers/