C ++ 11 Lambda Implementierung und Speichermodell

Ich möchte einige Informationen darüber erhalten, wie ich über C ++ 11-Abschlüsse und -Verfahren richtig nachdenken kannstd::function in Bezug darauf, wie sie implementiert sind 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. 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-Callback ist. Wenn die Umgebung jedoch entweder nach Wert oder nach Verweis erfasst wird, wird auf dem Stapel ein anonymes Objekt erstellt. Wenn eine Wertschließung von einer Funktion zurückgegeben werden muss, wird sie eingeschlossenstd::function. Was passiert in diesem Fall mit dem Schließungsspeicher? Wird es vom Stapel auf den Haufen kopiert? Ist es befreit, wenn diestd::function freigegeben wird, d. h. wie a referenziert wirdstd::shared_ptr?

Ich stelle mir vor, dass ich in einem Echtzeitsystem eine Kette von Lambda-Funktionen aufbauen und B als Fortsetzungsargument an A übergeben könnte, so dass eine Verarbeitungspipeline entstehtA->B geschaffen. In diesem Fall würden die Abschlüsse A und B einmal vergeben. Obwohl ich nicht sicher bin, ob diese auf dem Stapel oder dem Haufen 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, würde 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 echtzeitsicher sein wird. Ich möchte den Verarbeitungsblock A und dann B ausführen, wobei A sein Argument aufruft. Beide Funktionen kehren zurückstd::function Objekte, sof wird ein ... seinstd::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 eines, von dem ich denke, dass es schlecht ist, es in Echtzeit-Code zu verwenden:

for (t=0; t<1000; t++) {
    y = A(B)(t);
}

Und eines, bei dem wahrscheinlich Stapelspeicher 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 kostengünstig, da er genau wie ein Funktionsaufruf ist und keine Heap-Zuweisungen vorgenommen werden. Außerdem frage ich mich, ob ein Compiler die Schließung "aufheben" und Inlining-Optimierungen vornehmen könnte.

Ist das richtig? Vielen Dank.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage