zeitpunkt des lambda capturing



  • hallo,

    folgende >anomalie< hat mich soeben mit einiger debug-zeit beschert:

    #include <iostream> 
    int main()
    {
    	int i = 5;
    	auto f = [i](){ std::cout << i << '\n'; };
    	f();
    	i = 42;
    	f();
    }
    

    output:

    5
    5
    

    ich bin davon ausgegangen, dass alle value captured objekte bei jedem call neu kopiert werden. wenn ich nun die variable i per referenz uebergebe, damit das lambda immer den neusten wert zur verfuegung hat, so beeintraechtigt das die kapselung (das lambda hat non-const zugriff obwohl es nur liest). via const ref uebergeben ist ja leider auch nicht moeglich (wieso nicht eigentlich?).

    vorschlaege?

    LG



  • ritter_des_dunkeln schrieb:

    ich bin davon ausgegangen, dass alle value captured objekte bei jedem call neu kopiert werden.

    Wie soll das gehen?



  • Mechanics schrieb:

    ritter_des_dunkeln schrieb:

    ich bin davon ausgegangen, dass alle value captured objekte bei jedem call neu kopiert werden.

    Wie soll das gehen?

    so wie jede art von call-by-value. am beispiel von oben:
    f(); waere sozusagen die kurzschreibweise von f_(i); , wobei f_(int) das argument by value akzeptiert. dass das lambda zur zeit der definition eine kopie aller by-value-captures erstellt (und bis zur zerstoerung beibehaelt), ist fuer mich viel weniger naheliegend / intuitiv.



  • Versuch doch mal, einen per Referenz übergeben Wert zu ändern. Du wirst dich wundern...



  • manni66 schrieb:

    Versuch doch mal, einen per Referenz übergeben Wert zu ändern. Du wirst dich wundern...

    so?



  • Wenn das Lambda das i jedes Mal neu kopieren würde, hätte das allerdings unangenehme Konsequenzen: man könnte dann ein Lambda, das eine loakle Variable captured, nicht mehr außerhalb des Blocks verwenden, in dem die loakle Variable lebt.

    Code wie dieser hier würde nicht mehr funktionieren:

    #include <iostream>
    
    auto make_number_adder(int i) {
        return [i](int j) { return i + j; };
    }
    
    int main() {
        auto add2 = make_number_adder(2);
        auto add3 = make_number_adder(3);
        std::cout << add2(4) << ", " << add3(7) << '\n';
    }
    


  • ritter_des_dunkeln schrieb:

    manni66 schrieb:

    Versuch doch mal, einen per Referenz übergeben Wert zu ändern. Du wirst dich wundern...

    so?

    Ok, ich hätte geschworen, dass mutable auch für Referenzwerte benötigt wird.



  • wob schrieb:

    [...]

    das habe ich nicht bedacht, danke fuer das anschauliche beispiel. 👍



  • Etwas OT, ich meine aber dass in funktionalen Sprachen Bindings zu lokalen Namen gehen, die werden dann transparent am Leben gehalten.

    Falls OP also aus der funktionalen Ecke kommt, ist das eine legitime Falle. C++ kann das aber nicht, da ist alles Funktionale ja eh nur draufgebastelt 😉



  • manni66 schrieb:

    Ok, ich hätte geschworen, dass mutable auch für Referenzwerte benötigt wird.

    An den Fragesteller: hier ist nochmal Lektüre bzgl. const bei gecaptureten Variablen (ich könnte mir vorstellen, dass manni66 daran gedacht hat):
    http://aristeia.com/Papers/appearing%20and%20disappearing%20consts.pdf (ab S. 4) und
    http://scottmeyers.blogspot.de/2014/02/capture-quirk-in-c14.html



  • @namehier
    Das hat mit funktional oder nicht funktional nix zu tun, dabei geht's eher darum ob die Sprache nen GC verwendet oder nicht.

    EDIT: OK, den Elefanten hab' ich wiedermal übersehen... In einer funktionalen Sprache, wie soll man bitte den Unterschied feststellen ob eine Referenz oder eine Kopie in den Funktor gebunden wird?


Anmelden zum Antworten