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

How do you determine the size of the nodes created by a #39;std::map#39; for use with #39;boost::pool_allocator#39; (in a cross-platform way)?(您如何确定由 std::map 创建的节点的大小以与 boost::pool_allocator 一起使用(以跨平台方式)?)

本文介绍了您如何确定由 'std::map' 创建的节点的大小以与 'boost::pool_allocator' 一起使用(以跨平台方式)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新

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

Per comments, answer, and additional research, I have come to the conclusion that there is typically no difference between a set and a map in terms of node overhead. My question that follows is really:

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

How do you determine node overhead for convenient use of boost::pool_allocator as a custom allocator?

而且,进一步的更新:节点开销可能永远不会超过 4 个指针的大小,因此只需为 sizeof(T), sizeof(T)+sizeof(int), sizeof(T) + 2*sizeof(int), sizeof(T) + 3*sizeof(int)sizeof(T) + 4*sizeof(int)(或 int64_t 对于 64 位系统)应该没问题.这就是我实际在做的事情,而且很有效.

And, a further update: The node overhead is probably never going to be more than the size of 4 pointers, so just purging the Boost Pool for sizeof(T), sizeof(T)+sizeof(int), sizeof(T) + 2*sizeof(int), sizeof(T) + 3*sizeof(int) and sizeof(T) + 4*sizeof(int) (or int64_t for 64-bit systems) should be fine. That is what I am actually doing, and it works.

我想使用 增强内存池通过避免调用这些对象的析构函数来管理数以千万计的微小、相同大小的对象,而是在每个带包含许多实例的单个带中释放内存.

I want to use a boost memory pool to manage tens of millions of tiny, identically-sized objects by avoiding calls to the destructors of these objects, and instead freeing the memory in single swaths containing many instances per swath.

我发布了另一个关于这个问题的问题,这个问题的答案让我明白,我真正需要回答的问题就是我在这里提出的问题.

I posted another question about this issue, and the answer to that question has led me to understand that the question I really need to answer is the one I am asking here.

考虑以下代码:

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 析构函数,因为如上面链接的问题所述,自定义分配器的工作只是分配和释放内存,不是strong> 调用构造函数或析构函数.)

If you step into the purge_memory() function of the last line of code, you will see that the fast_pool_allocator nicely proceeds to free the memory from the system, just as desired. (No Obj destructors are called, because as noted in the linked question above, the job of the custom allocator is just to allocate and free memory, not to call constructors or destructors.)

它完全按预期工作.太棒了!

It works precisely as desired. Great!

然而,问题来了.如果将 set 替换为 map,然后尝试使用 boost::pool_allocator什么都不会发生在调用 purge_memory()!

However, here is the problem. If you replace the set with a map, and then try to use the boost::pool_allocator, nothing happens in the call to 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 代码 不同的 >不同要清除的单例内存池(假设请求的内存池存在,因为之前已经实例化).

As noted, the last line of code does nothing. The reason is that the boost::fast_pool_allocator is a singleton that only responds to, and manages memory for, objects of a given size that is fixed at compile-time. This is why the sizeof argument is used in the expression that calls purge_memory() - it tells the Boost Pool code which of the various different singleton memory pools to purge (assuming the requested one exists due to previously having been instantiated).

不幸的是,因为选择要清除的内存池是大小相关的,关键管理内部对象的大小(即,在通过调用自定义内存分配的内存中创建和销毁)分配器)是已知的.可悲的是,对于 std::mapmap 管理的内部对象的大小既不是 sizeof(Obj) 也不是 sizeof(std::pair).

Unfortunately, because the memory pool selected to be purged is size-dependent, it is critical that the size of the internal objects managed (i.e., created and destroyed in memory allocated via calls to the custom allocator) is known. Sadly, for std::map, the size of the internal objects managed by the map is neither sizeof(Obj) nor sizeof(std::pair<int const, Obj>).

我的问题是:你如何严格地,以一种根据 C++11 标准工作的跨平台方式,确定由 std::map 内部管理的对象的大小用于 boost::fast_pool_allocator?

My question is: How do you rigorously, and in a cross-platform way that works according to the C++11 standard, determine the size of the objects internally managed by std::map for use with boost::fast_pool_allocator?

这甚至可能吗?

推荐答案

没有真正的跨平台方式来推断您所追求的内容,因为每个地图实现都有自己的不满意之处,但通常是地图将在池中分配的节点.

There isn't a truly cross platform way to deduce what you are after, since every map implementation is unhappy in its own way, but generally it is the map node that will be allocated in the pool.

对于标准库的不同实现,这看起来不同,因此您的代码必须针对不同版本进行#ifdef-ed.有了脆弱性警告,以下是 g++/clang++/msc 编译器及其标准库的主要警告:

This looks different for the different implementations of the standard library, so you code will have to #ifdef-ed for the different versions. With a fragility warning in place, here are the main ones for the g++/clang++/msc compilers and their 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()

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

Here are some useful links for finding the necessary defines:

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

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

这篇关于您如何确定由 'std::map' 创建的节点的大小以与 'boost::pool_allocator' 一起使用(以跨平台方式)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

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

基础教程推荐