2016-07-29 20 views
6
Zuteilung

Gibt es eine Möglichkeit std::function in gcc zu verhindern, dynamisch Speicher für größere Funktionsobjekte Zuweisung?Prevent std :: Funktion in gcc aus dem Speicher oder Erhöhung Schwellen

Ich hätte den folgenden Code erwartet ohne dynamische Zuordnung zu arbeiten:

#include <functional> 
#include <iostream> 

// replace operator new and delete to log allocations 
void* operator new (std::size_t n) { 
    std::cout << "Allocating " << n << " bytes" << std::endl; 
    return malloc(n); 
} 
void operator delete(void* p) throw() { 
    free(p); 
} 

    class TestPlate 
    { 
    private: 
     int value; 

    public: 
     int getValue(){ return value; } 
     void setValue(int newValue) { value = newValue; } 

     int doStuff(const std::function<int()>& stuff) { return stuff(); } 

    }; 

int main() 
{ 
    TestPlate testor; 
    testor.setValue(15); 
    const std::function<int()>& func = std::bind(&TestPlate::getValue, &testor); 

    std::cout << testor.doStuff(func) << std::endl; 
    testor.setValue(25); 
    std::cout << testor.doStuff(func) << std::endl; 
} 

jedoch es 24 Byte zuweist. Soweit ich das beurteilen kann, benötigt der Zeiger auf die Methode 16 Bytes und der Zeiger auf die Klasseninstanz weitere 8 Bytes. Dies scheint entweder A größer als der interne Speicher für das Funktionsobjekt oder B ein einfacher Bug zu sein.

Ich frage mich, ob es eine Möglichkeit gibt, diese Art von Verhalten zu umgehen, ohne die Signatur des std::function zu ändern oder eine Menge zusätzlichen Wrapper-Code zu erstellen.

+0

Standard legt fest, dass _Implementations gefördert werden, um die Verwendung von dynamisch zugewiesenen Speichern für kleine aufrufbare Objekte zu vermeiden, zum Beispiel, wobei f ein Objekt zu halten. Compiler geben ihr Bestes. Wenn es nicht Ihren Bedürfnissen passt, gut ... – skypjack

+0

Klirren + libC++ zuteilt keine Speicher in Ihrem Beispiel (http://coliru.stacked-crooked.com/a/52505806440111db) – Praetorian

Antwort

6

Leider function GCC hat nur Platz für einen Zeiger auf Elementfunktion intern gespeichert, so das Ergebnis Ihrer bind Ausdruck passt nicht.

können Sie einen Lambda-Ausdruck verwenden, anstatt aber:

std::function<int()> f = [&]{ return testor.getValue(); }; 

Dies erfordert nur Platz für einen Verschluss eines Verweises auf testor (enthält, die die Hälfte der Größe eines Zeigers an das Mitglied ist, und ein Drittel der Größe des Bindungsergebnisses), und GCC definiert diese Schließung, so dass es in einem std::function gespeichert werden kann. nur einen Zeiger oder eine Referenz auf ein Objekt und eine Elementfunktion pointer_

+0

@ T.C. tatsächlich tue ich das - und das habe ich getestet. Aber nicht, was ich aus irgendeinem Grund hier eingegeben habe. Vielen Dank. –

0

Durch die außergewöhnlich skin-crawling functional Header von libstdC++ (die Standard-C++ - Bibliothek von GCC), fand ich heraus, dass es tatsächlich unmöglich ist, Heap-Zuordnungen mit seiner aktuellen Implementierung zu vermeiden. Es scheint einen speziellen Manager- und Aufrufer-Member zu haben, der Heap-zugeteilt ist, und es ist erforderlich, damit die Klasse funktioniert. Wenn du wirklich auf die Quelle schauen willst, here you go, dort sind definitiv schwarze Künste und Hexerei.

Es gibt einige Funktionen in der Kopfzeile, die die Übergabe in custom allocators geplant sind, aber sie scheinen zu diesem Zeitpunkt nicht implementiert werden.

In der Zwischenzeit könnten Sie Boost.function versuchen.

+0

wird es Heapzuordnung vermeiden, wenn Die Bedingung '__stored_locally' ist wahr. Leider ist das für etwas, das größer ist als ein Zeiger auf die Member-Funktion, falsch, so dass das und ein Zeiger auf ein Objekt nicht lokal gespeichert werden kann. –