我想创建unordered_map
(因为我特别需要哈希映射)。我想在开头分配它的最大尺寸(根据我的约束)
所以,如果我想分配256个条目,每个条目的大小是1B(只是一个例子。假设1Byte包括Key和Value)。然后我的unordered_map
键+条目的总大小为256B。我想在分配器中预先分配256B
然后,当unordered_map
将调用allocate()
/ deallocate()
时,allocator
将从已分配的内存中获取1B。
typedef boost::unordered::unordered_map<int, MyClass, boost::hash<int>, std::equal_to<MyClass>, ??? > > myMap
BOOST中是否存在?或其他地方?
----编辑----
正如我所看到的(感谢此处的答案) - 我的问题有两种解决方案:
实施allocator
,其中包含boost::pool<>
。此pool
内置于allocator
构造函数中。从allocate()
调用unordered_map
时,实际上会调用pool.malloc()
,而从deallocate()
调用unordered_map
时,实际上会调用pool.free()
。
使用已经实施的allocator
,例如pool_allocator
,如下所示:
typedef pool_allocator<std::pair<MyKey, MyClass>, boost::default_user_allocator_new_delete, boost::mutex, 1024 >) MyAllocator;
typedef unordered_map<MyKey, MyClass, hash, eq, MyAllocator> MyUnorderedMap;
我还不清楚秒选项,因为:
一个。我只能声明一个MyUnorderedMap吗?
湾如何在运行时声明大小不同next_block
1024
的新MyUnorderedMap?
答案 0 :(得分:4)
您所描述的内容实际上只能通过Boost Intrusive“Maps”(实际上,sets)来实现。
但是要获得真正的1B分配元素,您需要定义custom stateful value traits,因此您可以将元素有效负载分开存储节点索引元数据。
然而,从你声称元素类型为1B(对于具体的键和值类型显然永远不会是真的)这一事实,我不会假设你真的想要这个设计的解决方案“某种原因”。
相反,让我建议三种更普通的方法:
flat_map
flat_map
如果哈希查找不是必需的,您可以通过预先保留连续的元素存储并存储有序的地图来简化很多:
<强> Live On Coliru 强>
#include <boost/container/flat_map.hpp>
#include <iostream>
using Elements = boost::container::flat_map<std::string, std::string>;
int main() {
Elements map;
map.reserve(256); // pre-allocate 256 "nodes"!
map.insert({
{ "one", "Eins" },
{ "two", "Zwei" },
{ "three", "Drei" },
{ "four", "Vier" },
{ "five", "Fuenf" },
});
for (auto& e : map) {
std::cout << "Entry: " << e.first << " -> " << e.second << "\n";
}
std::cout << "map[\"three\"] -> " << map["three"] << "\n";
}
打印
Entry: five -> Fuenf
Entry: four -> Vier
Entry: one -> Eins
Entry: three -> Drei
Entry: two -> Zwei
map["three"] -> Drei
CAVEAT 侵入式容器有自己的权衡取舍。管理元素的底层存储可能容易出错。钩子的自动链接行为禁止
size()
和类似的(empty()
在某些无序集合配置上)的恒定时间实现,所以这可能不是你的事。
<强> Live On Coliru 强>
#include <boost/intrusive/unordered_set.hpp>
#include <boost/intrusive/unordered_set_hook.hpp>
#include <iostream>
namespace bi = boost::intrusive;
struct Element;
namespace boost {
template <> struct hash<Element> {
size_t operator()(Element const& e) const;
};
}
struct Element : bi::unordered_set_base_hook<> {
std::string key;
mutable std::string value;
Element(std::string k = "", std::string v = "")
: key(std::move(k)), value(std::move(v)) { }
bool operator==(Element const& other) const { return key == other.key; }
};
size_t boost::hash<Element>::operator()(Element const& e) const {
return hash_value(e.key);
}
using Elements = bi::unordered_set<Element>;
int main() {
std::array<Element, 256> storage; // reserved 256 entries
std::array<Elements::bucket_type, 100> buckets; // buckets for the hashtable
Elements hashtable(Elements::bucket_traits(buckets.data(), buckets.size()));
storage[0] = { "one", "Eins" };
storage[1] = { "two", "Zwei" };
storage[2] = { "three", "Drei" };
storage[3] = { "four", "Vier" };
storage[4] = { "five", "Fuenf" };
hashtable.insert(storage.data(), storage.data() + 5);
for (auto& e : hashtable) {
std::cout << "Hash entry: " << e.key << " -> " << e.value << "\n";
}
std::cout << "hashtable[\"three\"] -> " << hashtable.find({"three"})->value << "\n";
}
打印
Hash entry: two -> Zwei
Hash entry: four -> Vier
Hash entry: five -> Fuenf
Hash entry: three -> Drei
Hash entry: one -> Eins
hashtable["three"] -> Drei
如果您绝对需要基于节点的存储,请考虑使用自定义分配器。
¹你会注意到(至少在Boost的unordered_map实现中)分配器用于两个类型(桶指针和值节点),因此有两个可能的固定大小分配。
(参见样本底部的清理调用)
<强> Live On Coliru 强>
#include <boost/pool/pool_alloc.hpp>
#include <boost/unordered/unordered_map.hpp>
#include <iostream>
using RawMap = boost::unordered_map<std::string, std::string>;
using Elements = boost::unordered_map<
std::string, std::string,
RawMap::hasher, RawMap::key_equal,
boost::fast_pool_allocator<RawMap::value_type>
>;
int main() {
{
Elements hashtable;
hashtable.insert({
{ "one", "Eins" },
{ "two", "Zwei" },
{ "three", "Drei" },
{ "four", "Vier" },
{ "five", "Fuenf" },
});
for (auto& e : hashtable) {
std::cout << "Hash entry: " << e.first << " -> " << e.second << "\n";
}
std::cout << "hashtable[\"three\"] -> " << hashtable.find("three")->second << "\n";
}
// OPTIONALLY: free up system allocations in fixed size pools
// Two sizes, are implementation specific. My 64 system has the following:
boost::singleton_pool<boost::fast_pool_allocator_tag, 8>::release_memory(); // the bucket pointer allocation
boost::singleton_pool<boost::fast_pool_allocator_tag, 32>::release_memory(); // the ptr_node<std::pair<std::string const, std::string> >
}