Ich versuche, einen einfachen Speicherpoolzuordner mit std::unordered_map
zu verwenden. Ich habe diesen gleichen Zuordner scheinbar erfolgreich mit std::string
und std::vector
verwendet. Ich möchte, dass die in der unordered_map (und dem Vektor) enthaltenen Elemente diesen Zuordner auch verwenden, sodass ich meinen Zuordner in std::scoped_allocator_adaptor
eingepackt habe.Verwenden eines benutzerdefinierten Zuordners in einem std :: scoped_allocator_adaptor mit Std :: unordered_map
vereinfachte Definition set:
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>>>;
Initialised als solche:
lake pool;
mm_map map { mm_alloc<std::pair<mm_string, mm_vector>>{pool} };
lake_alloc
ist unten mit dem Rest des Iterators Code dargestellt. Der Fehler, den ich in Clang 3.3 bekomme, ist, dass es nicht allocator_type
(in diesem Fall der mm_alloc des Paares von String zu Vektor) zu seinem eigenen __pointer_allocator
. Dies ist ein interner Typ, der für die Hash-Map-Implementierung verwendet wird. Partielle Fehlerausgabe unter:
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 gibt mir einen ähnlichen Fehler in seiner Hash-Karte internen Strukturen so klar es mache ich falsch, aber das ist mein erster Ausflug in Verteilern in der STL und ich bin ratlos.
Der benutzerdefinierte Zuordner folgt, Es ist eine einfache Implementierung mit einigen Löchern, aber diese Version funktioniert gut in einem enthaltenen Testfall mit ein paar Mega Daten in Vektoren und Strings.
#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>;
hast du std :: hash und std :: equal_to auf deine benutzerdefinierten Typen spezialisiert? – sehe
Nur eine Frage, warum verwenden Sie einen 'scoped_allocator_adaptor', wenn Sie die verschachtelten Zuordner manuell definieren? Ist es nicht der springende Punkt, dass Sie die Allokatoren auf einmal definieren? –
Konrad, die Beispiele, die ich bisher gefunden habe, spezifizieren den Allokator explizit für jedes Level, aber es gibt eine gute Chance, dass mir etwas fehlt. Siehe z.B. Bjarnes Aufnahme bei: http://www.stroustrup.com/C++11FAQ.html#scoped-allocator – zenmumbler