繁体   English   中英

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

[英]How do you determine the size of the nodes created by a 'std::map' for use with 'boost::pool_allocator' (in a cross-platform way)?

更新

根据评论,答案和其他研究,我得出的结论是,就节点开销而言, setmap之间通常没有区别。 我的以下问题确实是:

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

并且,进一步更新 :节点开销可能永远不会超过4个指针的大小,因此只需清除Boost Pool中的sizeof(T)sizeof(T)+sizeof(int)sizeof(T) + 2*sizeof(int)sizeof(T) + 3*sizeof(int)sizeof(T) + 4*sizeof(int) (或对于64位系统为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可以按照fast_pool_allocator很好地从系统中释放内存。 (没有调用Obj析构函数,因为如上面链接的问题所述,自定义分配器的工作只是分配和释放内存, 而不是调用构造函数或析构函数。)

它完全可以按需工作。 大!

但是,这就是问题所在。 如果将set替换为map ,然后尝试使用boost::pool_allocator ,则对purge_memory()的调用不会发生任何 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();

如前所述,最后一行代码不执行任何操作 原因是boost::fast_pool_allocator是一个单例,仅对在编译时固定的给定大小的对象进行响应并管理其内存。 这就是为什么在调用purge_memory()的表达式中使用sizeof参数的原因-它告诉Boost Pool代码清除各种不同的单例内存池中的一个(假定由于先前已实例化而存在请求的内存池)。

不幸的是,由于选择要清除的内存池取决于大小,因此至关重要的是,要了解(即在通过调用自定义分配器分配的内存中创建和销毁的)内部对象的大小。 可悲的是,对于std::map ,由map管理的内部对象的大小既不是sizeof(Obj)也不是sizeof(std::pair<int const, Obj>)

我的问题是:如何严格按照以C ++ 11标准运行的跨平台方式,确定由std::map内部管理以供boost::fast_pool_allocator使用的对象的大小?

这有可能吗?

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

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

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);

在我的系统上,我得到以下输出:

分配器大小of(T)== 32

没有一种真正的跨平台方法可以推断出您要执行的操作,因为每个地图实现都不满意,但是通常将在池中分配地图节点。

对于标准库的不同实现,这看起来有所不同,因此对于不同的版本,您的代码将必须#ifdef -ed。 带有易碎性警告之后,以下是g ++ / clang ++ / msc编译器及其std库的主要警告:

// 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/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM