我正在尝试使用带有std::unordered_map
的简单内存池分配器。我使用std::string
和std::vector
看似成功的同一个分配器。我希望unordered_map(和vector)中包含的项目也使用这个分配器,所以我将我的分配器包装在std::scoped_allocator_adaptor
中。
简化的定义集:
template <typename T>
using mm_alloc = std::scoped_allocator_adaptor<lake_alloc<T>>;
using mm_string = std::basic_string<char, std::char_traits<char>, mm_alloc<char>>;
using mm_vector = std::vector<mm_string, mm_alloc<mm_string>>;
using mm_map = std::unordered_map<mm_string, mm_vector, std::hash<mm_string>, std::equal_to<mm_string>, mm_alloc<std::pair<mm_string, mm_vector>>>;
初始化如下:
lake pool;
mm_map map { mm_alloc<std::pair<mm_string, mm_vector>>{pool} };
lake_alloc
如下所示,其余的迭代器代码。我在Clang 3.3中得到的错误是它不能将allocator_type
(在这种情况下,该对字符串的mm_alloc)转换为它自己的__pointer_allocator
。这是用于哈希映射实现的内部类型。下面的部分错误输出:
lib/c++/v1/__hash_table:848:53: error: no matching conversion for functional-style
cast from 'const allocator_type' (aka 'const std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<std::__1::pair<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<char, krystal::lake> > >, std::__1::vector<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<char, krystal::lake> > >,
std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<char, krystal::lake> > >, krystal::lake> > > >, krystal::lake> >') to '__pointer_allocator' (aka
'std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<std::__1::__hash_node<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<char, krystal::lake> > >, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<char, krystal::lake> > >, std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::scoped_allocator_adaptor<krystal::krystal_alloc<char, krystal::lake> > >, krystal::lake> > > >, void *> *, krystal::lake> >')
: __bucket_list_(nullptr, __bucket_list_deleter(__pointer_allocator(__a), 0)),
^~~~~~~~~~~~~~~~~~~~~~~
GCC 4.7.1在哈希映射内部结构中给出了类似的错误,所以我做错了,但这是我第一次尝试STL中的分配器,我不知所措。
自定义分配器如下所示,这是一个带有一些漏洞的简单实现,但是这个版本在包含测试的情况下运行良好,在向量和字符串中有几个megs的数据。
#include <cstddef>
#include <memory>
#include <scoped_allocator>
class lake {
const size_t block_size_;
mutable std::vector<std::unique_ptr<uint8_t[]>> blocks_;
mutable uint8_t *arena_, *pos_;
static constexpr const size_t DefaultBlockSize = 48 * 1024;
void add_block(size_t of_size) const {
blocks_.emplace_back(new uint8_t[of_size]);
pos_ = arena_ = blocks_.back().get();
}
inline void add_block() const { add_block(block_size_); }
public:
lake(const size_t block_size)
: block_size_ {block_size}
{
add_block();
}
lake() : lake(DefaultBlockSize) {}
void* allocate(size_t n) const {
if (pos_ + n - arena_ > block_size_) {
if (n > block_size_)
add_block(n); // single-use large block
else
add_block();
}
auto result = pos_;
pos_ += n;
return result;
}
void deallocate(void* p, size_t n) const {
}
};
template <typename T, typename Alloc>
class krystal_alloc {
const Alloc* allocator_;
public:
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
template <typename U>
struct rebind { typedef krystal_alloc<U, Alloc> other; };
krystal_alloc() : allocator_{ new Alloc() } {} // not used
krystal_alloc(const Alloc& alloc) : allocator_{ &alloc } {}
pointer address(reference v) {
return 0;
}
const_pointer address(const_reference v) {
return 0;
}
size_type max_size() const {
return static_cast<size_type>(-1) / sizeof(value_type);
}
pointer allocate(size_type n) {
return static_cast<pointer>(allocator_->allocate(sizeof(T) * n));
}
void deallocate(pointer p, size_type n) {
allocator_->deallocate(p, n);
}
};
template <typename T, typename Alloc, typename U>
inline bool operator==(const krystal_alloc<T, Alloc>&, const krystal_alloc<U, Alloc>) { return true; }
template <typename T, typename Alloc, typename U>
inline bool operator!=(const krystal_alloc<T, Alloc>&, const krystal_alloc<U, Alloc>) { return false; }
// -- standard usage
template <typename T>
using lake_alloc = krystal_alloc<T, lake>;
答案 0 :(得分:8)
我认为基本错误是你的krystal_alloc缺少“转换构造函数”:
template <class U>
krystal_alloc(const krystal_alloc<U, Alloc>& u)
: allocator_(u.allocator_) {}
我不确定我是否正确实现了,这只是我最好的猜测。你需要一个朋友声明来完成这项工作:
template <class U, class A> friend class krystal_alloc;
另外,我建议你在unordered_map的分配器中为key_type添加“const”:
using mm_map = std::unordered_map<mm_string, mm_vector, std::hash<mm_string>,
std::equal_to<mm_string>,
mm_alloc<std::pair<const mm_string, mm_vector>>>;
我认为您可以在内部容器上使用lake_alloc
而不是mm_alloc
。你的例子为我编译两种方式。我没有测试它的运行时行为。