Ich möchte einige Informationen darüber, wie man richtig über C ++ 11-Schließungen nachdenkt und std::function
wie sie implementiert werden und wie mit Speicher umgegangen wird.
Obwohl ich nicht an vorzeitige Optimierung glaube, habe ich die Angewohnheit, die Auswirkungen meiner Auswahl auf die Leistung beim Schreiben von neuem Code sorgfältig zu berücksichtigen. Ich programmiere auch ziemlich viel in Echtzeit, z. B. auf Mikrocontrollern und für Audiosysteme, bei denen nicht deterministische Speicherzuweisungs- / Freigabepausen vermieden werden sollen.
Daher möchte ich ein besseres Verständnis dafür entwickeln, wann C ++ - Lambdas verwendet werden sollen oder nicht.
Mein derzeitiges Verständnis ist, dass ein Lambda ohne erfassten Verschluss genau wie ein C-Rückruf ist. Wenn die Umgebung jedoch entweder nach Wert oder nach Referenz erfasst wird, wird ein anonymes Objekt auf dem Stapel erstellt. Wenn ein Wertabschluss von einer Funktion zurückgegeben werden muss, wird er eingebunden std::function
. Was passiert in diesem Fall mit dem Schließspeicher? Wird es vom Stapel auf den Heap kopiert? Wird es freigegeben, wenn das std::function
freigegeben wird, dh wird es wie ein Referenzzähler gezählt std::shared_ptr
?
Ich stelle mir vor, dass ich in einem Echtzeitsystem eine Kette von Lambda-Funktionen einrichten und B als Fortsetzungsargument an A übergeben könnte, damit eine Verarbeitungspipeline A->B
erstellt wird. In diesem Fall würden die A- und B-Schließungen einmal zugewiesen. Obwohl ich nicht sicher bin, ob diese auf dem Stapel oder dem Heap zugeordnet werden würden. Im Allgemeinen scheint dies jedoch in einem Echtzeitsystem sicher zu sein. Wenn B andererseits eine Lambda-Funktion C konstruiert, die es zurückgibt, wird der Speicher für C wiederholt zugewiesen und freigegeben, was für die Echtzeitnutzung nicht akzeptabel wäre.
Im Pseudocode eine DSP-Schleife, die meiner Meinung nach in Echtzeit sicher sein wird. Ich möchte den Verarbeitungsblock A und dann B ausführen, wobei A sein Argument aufruft. Beide Funktionen geben std::function
Objekte zurück, also f
ein std::function
Objekt, in dem seine Umgebung auf dem Heap gespeichert ist:
auto f = A(B); // A returns a function which calls B
// Memory for the function returned by A is on the heap?
// Note that A and B may maintain a state
// via mutable value-closure!
for (t=0; t<1000; t++) {
y = f(t)
}
Und eine, von der ich denke, dass sie im Echtzeitcode schlecht zu verwenden ist:
for (t=0; t<1000; t++) {
y = A(B)(t);
}
Und einer, bei dem meiner Meinung nach der Stapelspeicher wahrscheinlich für den Abschluss verwendet wird:
freq = 220;
A = 2;
for (t=0; t<1000; t++) {
y = [=](int t){ return sin(t*freq)*A; }
}
Im letzteren Fall wird der Abschluss bei jeder Iteration der Schleife erstellt, aber im Gegensatz zum vorherigen Beispiel ist er billig, da er wie ein Funktionsaufruf ist und keine Heap-Zuweisungen vorgenommen werden. Außerdem frage ich mich, ob ein Compiler den Verschluss "aufheben" und Inlining-Optimierungen vornehmen könnte.
Ist das richtig? Danke dir.
std::function
der Status auf dem Haufen gespeichert ist oder nicht, und hat nichts mit Lambdas zu tun. Ist das richtig?
std::function
!!
auto
Rückgabetyp zurückgeben.
operator()
. Es gibt kein "Heben", Lambdas sind nichts Besonderes. Sie sind nur eine Abkürzung für ein lokales Funktionsobjekt.