2013-07-07 23 views
8

私はstd::unordered_mapで単純なメモリプールアロケータを使用しようとしています。私はこの同じアロケータをstd::stringとの両方でうまく使うことができました。私はstd::scoped_allocator_adaptorに私のアロケータをラップしたので、unordered_map(とベクトル)に含まれる項目もこのアロケータを使用したいと思います。std :: unordered_mapで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でアロケータで私の最初の進出であると私は途方に暮れて。

カスタムアロケータはそれに続くいくつかの穴がある単純な実装ですが、このバージョンはベクタと文字列の数メガのデータを含むテストケースでうまくいきます。

#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

カスタムタイプにstd :: hashとstd :: equal_toを特化しましたか? – sehe

+1

ちょうど1つの質問ですが、どうしてネストされたアロケータを手動で定義している場合は、 'scoped_allocator_adaptor'を使用していますか?アロケータを一度に定義することの全体的なポイントではありませんか? –

+0

Konradは、これまでにすべてのレベルで明示的にアロケータを指定していましたが、何か不足している可能性があります。例えば、 Bjarneさんのテイク:http://www.stroustrup.com/C++11FAQ.html#scoped-allocator – zenmumbler

答えて

8

私は基本的なエラーがあなたのkrystal_allocは「変換コンストラクタを」欠けていることであると信じて:

template <class U> 
    krystal_alloc(const krystal_alloc<U, Alloc>& u) 
     : allocator_(u.allocator_) {} 

私はそれを正しく実装わからない、それはちょうど私の最高の推測です。あなたはこの仕事をするために友人の声明をする必要があります。また、私はあなたがunordered_mapのためにあなたのアロケータにkey_typeに「CONST」を追加することをお勧めします

template <class U, class A> friend class krystal_alloc; 

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>>>; 

そして、私はを考えること内部容器にmm_allocの代わりにlake_allocを使用することができます。あなたの例は私のために両方の方法でコンパイルされます。私はランタイムの動作のためにそれをテストしませんでした。

+0

ありがとう、それは確かに問題でした。スコープ付きアロケータを削除することを試しています。この場合、必要ではないようです。他の人たちのために、私はここで見ていたはずです.http://www.cplusplus.com/reference/memory/allocator_traits/ – zenmumbler

関連する問題