2015-09-15 8 views
8

Ich spiele mit Std :: Funktion und benutzerdefinierte Allokatoren, aber es verhält sich nicht wie erwartet, wenn ich die Funktion nicht mit einem anfänglichen Funktor zur Verfügung stellen.Was ist der Punkt des Konstruktors std :: function mit benutzerdefiniertem Zuordner, aber keine anderen Argumente?

Wenn ich dem Konstruktor einen benutzerdefinierten Zuordner, aber keinen anfänglichen Funktor zur Verfügung stelle, wird der Zuordner niemals verwendet, oder so scheint es.

Dies ist mein Code.

//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); 
} 

Ausgang:

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 

So case1: MyFunction1 teilt mit allocator1 wie erwartet.

case2: myFunction2 wird im Konstruktor allocator2 zugewiesen, aber wenn ein Funktor zugewiesen wird, scheint er auf den standardmäßigen std :: allocator zurückgesetzt zu werden, um die Zuweisung vorzunehmen (daher kein Ausdruck über Zuweisung).

case3: myFunction3 erhält im Konstruktor allocator3, aber bei Zuordnung von myFunction1 erfolgt die Zuweisung mit dem Zuweisungsmodul von function1, um die Zuweisung vorzunehmen.

Ist das korrektes Verhalten? Insbesondere im Fall 2, warum zurück zur Verwendung von Standard-std :: allocator? Wenn ja, was ist der Punkt des leeren Konstruktors, der einen Zuordner verwendet, da der Zuordner niemals verwendet wird.

Ich verwende VS2013 für diesen Code.

Meine Allocator Klasse ist nur eine minimale Implementierung, die neu verwendet und sich abmeldet, wenn es

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

Es gibt einen Vorschlag allocator Unterstützung von 'std :: function' zu entfernen: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0302r0.html einer hilfreichen Liste Bekannte Probleme –

Antwort

5

std::function ‚s allocator Unterstützung ordnet ist ... seltsam. Die aktuelle Spezifikation für operator=(F&& f) lautet: std::function(std::forward<F>(f)).swap(*this);. Wie Sie sehen können, bedeutet dies, dass Speicher für f zugewiesen wird, wobei std::function standardmäßig verwendet wird, und nicht der Zuweiser, der zum Erstellen von *this verwendet wurde. Das Verhalten, das Sie beobachten, ist korrekt, aber überraschend.

Darüber hinaus, da die (allocator_arg_t, Allocator) und (allocator_arg_t, Allocator, nullptr_t) Konstruktoren noexcept sind, können sie nicht wirklich den Zuordner speichern, auch wenn sie wollten (Typ-Löschen eines Zuweisers erfordert möglicherweise eine dynamische Zuordnung). Wie es ist, sind sie im Grunde No-Ops, die vorhanden sind, um das Nutzungszuweiser-Konstruktionsprotokoll zu unterstützen.

LWG vor kurzem abgelehnt an issue, die dieses Verhalten ändern würde.

+0

Sie zahlen Lippenbekenntnis zu dem usser-allocator-Konstruktionsprotokoll (und 'std :: scoped_allocator_adaptor'), aber sie unterstützen es tatsächlich nicht. Vielleicht entscheidet der GCC deshalb, den Lippenbekenntnis nicht umzusetzen. Ich schlage eine alternative Lösung vor: http://bit.ly/allocfun (PDF). – Potatoswatter

+0

ist vorgesehen, dass ein aufrufbare Objekt gespeichert in 'std :: function' sollte vom allocator gelöscht werden, die' std :: function' benutzen? Oder einfach 'delete p' verwenden? – linux40

+0

@ linux40 Zuweiser kann das nicht 'construct' oder' destroy' auf beliebige Typen nach Typ Löschung (siehe aber [LWG2502] (http: // WG21.link/LWG2502), die von 'construct' spricht, aber auch für' destroy' gilt. Die Freigabe muss offensichtlich unter Verwendung des Zuweisers erfolgen; Der Destruktor wird wahrscheinlich nur direkt aufgerufen. –

Verwandte Themen