2015-09-15 7 views
8

私はstd :: functionとカスタムアロケータで遊んでいますが、最初のファンクタを備えていないときに期待通りの動作をしません。カスタムアロケータを持つstd :: functionコンストラクタのポイントは何ですか?他のargはありません。

コンストラクタにカスタムアロケータを提供するが、初期ファンクタを使用しないときは、アロケータは使用されないか、そうでないようです。

これは私のコードです。

//Simple functor class that is big to force allocations 
struct Functor128 
{ 
    Functor128() 
    {} 

    char someBytes[128]; 

    void operator()(int something) 
    { 
     cout << "Functor128 Called with value " << something << endl; 
    } 
}; 

int main(int argc, char* argv[]) 
{ 
Allocator<char, 1> myAllocator1; 
Allocator<char, 2> myAllocator2; 
Allocator<char, 3> myAllocator3; 
Functor128 myFunctor; 

cout << "setting up function1" << endl; 
function<void(int)> myFunction1(allocator_arg, myAllocator1, myFunctor); 
myFunction1(7); 

cout << "setting up function2" << endl; 
function<void(int)> myFunction2(allocator_arg, myAllocator2); 
myFunction2 = myFunctor; 
myFunction2(9); 

cout << "setting up function3" << endl; 
function<void(int)> myFunction3(allocator_arg, myAllocator3); 
myFunction3 = myFunction1; 
myFunction3(19); 
} 

出力:

setting up function1 
Allocator 1 allocating 136 bytes. 
Functor128 Called with value 7 

setting up function2 
Functor128 Called with value 9 

setting up function3 
Allocator 1 allocating 136 bytes. 
Functor128 Called with value 19 

だから、ケース1:myFunction1は予想通りallocator1使用して割り当てます。

case2:myFunction2はコンストラクタでallocator2が与えられますが、ファンクタが割り当てられている場合は、デフォルトのstd :: allocatorを使用して割り当てを行うように再設定されているように見えます(割り当てについてはプリントアウトしません)。

case3:myFunction3はコンストラクタでallocator3が与えられますが、myFunction1から割り当てられると、割り当てはfunction1のアロケータを使用して割り当てが行われます。

この動作は正しいですか? 特に、ケース2の場合、デフォルトのstd :: allocatorを使用するのはなぜですか? その場合、アロケータを使用する空のコンストラクタのポイントは、アロケータとして使用されません。

私はこのコードにVS2013を使用しています。

私のアロケータクラスは奇妙な...新しい使用しており、それが

template<typename T, int id = 1> 
class Allocator { 
public: 
    // typedefs 
    typedef T value_type; 
    typedef value_type* pointer; 
    typedef const value_type* const_pointer; 
    typedef value_type& reference; 
    typedef const value_type& const_reference; 
    typedef std::size_t size_type; 
    typedef std::ptrdiff_t difference_type; 

public: 
    // convert an allocator<T> to allocator<U> 
    template<typename U> 
    struct rebind { 
     typedef Allocator<U> other; 
    }; 

public: 
    inline Allocator() {} 
    inline ~Allocator() {} 
    inline Allocator(Allocator const&) {} 
    template<typename U> 
    inline Allocator(Allocator<U> const&) {} 

    // address 
    inline pointer address(reference r) { return &r; } 
    inline const_pointer address(const_reference r) { return &r; } 

    // memory allocation 
    inline pointer allocate(size_type cnt, 
     typename std::allocator<void>::const_pointer = 0) 
    { 
     size_t numBytes = cnt * sizeof (T); 
     std::cout << "Allocator " << id << " allocating " << numBytes << " bytes." << std::endl; 
     return reinterpret_cast<pointer>(::operator new(numBytes)); 
    } 
    inline void deallocate(pointer p, size_type) { 
     ::operator delete(p); 
    } 

    // size 
    inline size_type max_size() const { 
     return std::numeric_limits<size_type>::max()/sizeof(T); 
    } 

    // construction/destruction 
    inline void construct(pointer p, const T& t) { new(p)T(t); } 
    inline void destroy(pointer p) { p->~T(); } 

    inline bool operator==(Allocator const&) { return true; } 
    inline bool operator!=(Allocator const& a) { return !operator==(a); } 
}; // end of class Allocator 
+0

アロケータサポートを 'std :: function'から削除する提案があります:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0302r0.html既知の問題 –

答えて

5

std::functionのアロケータのサポートがある割り振るときにログアウトするだけの最小限の実装です。

operator=(F&& f)の現在の仕様はstd::function(std::forward<F>(f)).swap(*this);です。これは、*thisの構築に使用したアロケータではなく、std::functionがデフォルトで使用するものを使用して、fのメモリが割り当てられていることを示しています。あなたが観察する行動は正しいが、驚くべきことだ。

また、(allocator_arg_t, Allocator)(allocator_arg_t, Allocator, nullptr_t)のコンストラクタはnoexceptであるため、実際にはアロケータを格納することはできません(アロケータの型消去は動的割り当てが必要な場合もあります)。つまり、それらは、基本的には、アロケータ構築プロトコルをサポートするために存在するノーオプです。

LWGは最近、この動作を変更するan issueを拒否しました。

+0

彼らは使用アロケータ構築プロトコル(と 'std :: scoped_allocator_adaptor')にリップサービスを支払うが、実際にはそれをサポートしていない。おそらくこれがGCCが口唇サービスを実装しないことを選択した理由です。私は代替ソリューションを提案しています:http://bit.ly/allocfun(PDF)。 – Potatoswatter

+0

'std :: function'で保存された呼び出し可能オブジェクトは、' std :: function'が使用するアロケータによって削除されるべきですか?あるいは 'delete p'を使うだけですか? – linux40

+0

@ linux40アロケータは、タイプ消去後に任意のタイプに対して 'construct'や' destroy'を行うことはできません(しかし、[LWG2502](http:// wg21。link/LWG2502)、これは 'construct'について語っていますが、' destroy'にも等しく適用されます)。割り振り解除は明らかにアロケーターを使用して行わなければなりません。デストラクタはたぶん直接呼び出されるだけでしょう。 –

関連する問題