更新
根据评论,回答和其他研究,我得出的结论是,set
和map
在节点开销方面通常没有区别。接下来我的问题是:
如何确定节点开销以方便使用
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}一起使用}}?
这甚至可能吗?
答案 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()
以下是一些有用的链接,用于查找必要的定义: