Tôi đang cố gắng sử dụng một bộ cấp phát pool bộ nhớ đơn giản với std::unordered_map
. Tôi đã sử dụng cùng một trình phân bổ này dường như thành công với cả hai số std::string
và std::vector
. Tôi muốn các mục chứa trong unordered_map (và vectơ) cũng sử dụng phân bổ này vì vậy tôi đã bọc phần cấp phát của tôi trong std::scoped_allocator_adaptor
.Sử dụng một trình phân bổ tùy chỉnh bên trong một std :: scoped_allocator_adaptor với std :: unordered_map
Giản đặt định nghĩa:
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>>>;
khởi như vậy:
lake pool;
mm_map map { mm_alloc<std::pair<mm_string, mm_vector>>{pool} };
lake_alloc
được hiển thị bên dưới với phần còn lại của mã iterator. Lỗi tôi nhận được trong Clang 3.3 là nó không thể allocator_type
(trong trường hợp này là mm_alloc của cặp chuỗi thành vectơ) thành __pointer_allocator
của riêng nó. Đó là loại nội bộ được sử dụng để triển khai bản đồ băm. đầu ra lỗi phần dưới đây:
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 mang lại cho tôi một lỗi tương tự trong bản đồ băm cấu trúc nội bộ của mình như vậy rõ ràng tôi đang làm nó sai, nhưng đây là bước đột phá đầu tiên của tôi trong allocators trong STL và tôi thua lỗ.
Trình phân bổ tùy chỉnh theo sau, Đây là một triển khai đơn giản với một số lỗ trong đó, nhưng phiên bản này hoạt động tốt trong một trường hợp thử nghiệm chứa một vài megs dữ liệu trong vectơ và chuỗi.
#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>;
bạn có chuyên về std :: hash và std :: equal_to cho các loại tùy chỉnh của bạn không? – sehe
Chỉ một câu hỏi, tại sao bạn lại sử dụng 'scoped_allocator_adaptor' nếu bạn định nghĩa các trình phân bổ lồng nhau theo cách thủ công? Không phải là toàn bộ vấn đề mà bạn định nghĩa các nhà phân phối trong một lần? –
Konrad, các ví dụ tôi đã tìm thấy cho đến nay tất cả chỉ định cấp phát một cách rõ ràng cho mỗi cấp, nhưng có một cơ hội tốt tôi thiếu một cái gì đó. Xem ví dụ Bjarne lấy tại: http://www.stroustrup.com/C++11FAQ.html#scoped-allocator – zenmumbler