2016-05-16 7 views
0

Ich habe versucht herauszufinden, wie Lambda in C++ funktioniert.Lambda erfasst unerwartete Variablen

Und etwas Seltsames passiert ist. Es ist so komisch, dass ich nicht weiß, wie ich es richtig beschreiben soll. Ich habe versucht, mehrere Schlüsselwörter zu googlen, aber fand nichts das Verhalten erwähnt.

Ich versuchte zuerst this code.

#include <iostream> 
#include <utility> 
using namespace std ; 

auto func() { 
    int a = 0 ; 

    auto increase = [ &a ](int i = 1){ a += i ; } ; 
    auto print = [ &a ](){ cout << a << '\n' ; } ; 

    pair< decltype(increase), decltype(print) > 
    p = make_pair(increase, print) ; 
    return p ; 
} 

int main() { 
    auto lambdas = func() ; 

    auto increase = lambdas.first ; 
    auto print = lambdas.second ; 

    print() ; 
    increase() ; 
    print() ; 
    increase(123456) ; 
    print() ; 

    return 0; 
} 

Der Ausgang wird wie erwartet als

-1218965939 
-1218965938 
-1218842482 

aber nachdem ich diese in die 'Func()' hinzufügen

cout << typeid(decltype(print)).name() << '\n' 
    << typeid(decltype(increase)).name() << '\n' ; 

wie this one

der Ausgang wurde

Z4funcvEUlvE0_ 
Z4funcvEUliE_ 
0 
1 
123457 

Ich habe nicht erwartet zu passieren.

[UPDATE]

Die Variable a sollte "tot" hat, weil sein Lebenszyklus beendet wurde.

Aber ich bin neugierig, warum die Code-Prüfungen typeid und decltype Ursache a schienen wiederbelebt werden?

+0

In einer anderen Anmerkung, 'auto erhöhen = [& a] (int i = 1) {a + = i; }; 'Dieser Standardparameter sollte verboten sein. Nicht sicher, warum es nicht ist. – user4581301

+0

@ user4581301 Ich fand [dies] (http://stackoverflow.com/a/35831564/5161420), obwohl ich 'auto' nicht verwendet habe. – kaltu

+0

Ah. Wieder einmal ist mein Wissen veraltet. Vielen Dank! – user4581301

Antwort

2

Reine Chance.

Wie Sie vermutlich wissen, drucken Sie nicht spezifizierte Werte über eine freie Referenz.

  • In Ihrem ersten Beispiel versucht die baumelnden Referenz von einem Speicherplatz zu „lesen“, die für etwas anderes, da wiederverwendet wurde.

  • In Ihrem zweiten Beispiel die cout s und/oder typeid s haben die blutigen Eingeweiden der Umsetzung Ihrer kompilierte Programm so beeinflusst, dass der Speicherplatz von a durch die Zeit, drucken Sie illegal seine sein unberührt geschieht Wert.

Aber es gibt keinen Punkt bei dem Versuch, über diese noch weiter zu rationalisieren, und man konnte ein anderes Ergebnis das nächste Mal starten Sie das Programm. Oder Ihr Computer könnte explodieren. Oder die Zeitachse könnte so verändert werden, dass du nie geboren wurdest. Versuchen Sie nicht, die Symptome von UB — einfach zu vermeiden.

4

Sie sind durch Bezugnahme an a gebunden. Dies ist jedoch eine lokale Variable, die auf dem Stack gespeichert wird. Es ist undefiniertes Verhalten, um darauf zuzugreifen, sobald die Funktion die Ausführung beendet hat.

Es ist das gleiche wie wenn Sie einen Zeiger auf a zurückgegeben und dann von dem Aufrufer verwendet.

+0

Ich denke das OP weiß das und das beantwortet die Frage nicht. –

3

Keine der Ausgaben von Ihrem Programm ist "wie erwartet".

Die Lambdas in func() Erfassung durch Verweis eine lokal begrenzte Variable, die außerhalb des Geltungsbereichs geht, sobald func() zurückgibt.

Nach func() zurückgibt, ist a nicht mehr vorhanden, wie jedes andere function-local scope-Objekt. Daher werden ihre erfaßten Referenzen jetzt auf ein Objekt bezogen, das den Gültigkeitsbereich verlassen hat und zerstört wurde, und jede Verwendung des Referencend-Werts wird zu undefiniertem Verhalten.

Schlimmer noch, der Code legt auch den Wert über die nicht länger gültige Referenz fest. Bei der herkömmlichen Implementierung wird dies über einen zufälligen Teil des Stapels geschrieben, was zum Absturz des gesamten Prozesses führen kann.

+0

Schlimmer, es könnte nicht abstürzen, stattdessen könnte es eine Sprung- oder Rücksprungadresse überschreiben, zu einem zufälligen Platz im Speicher springen, der 'DeleteFile' mit einem Dateinamen zu nennen scheint ... –

+0

Ich denke, das OP weiß das und das tut es nicht ' t die Frage beantworten. Wohlgemerkt, meins sagt effektiv: "Suche keine Antwort auf diese Frage", was auch keine große Antwort ist: P –

Verwandte Themen