2017-03-10 5 views
4

Ich habe ein Callback-System, das Lambda hält, wenn etwas passiert. Um benachrichtigt zu werden, müssen Sie das Lambda für eine Kennung registrieren oder die Registrierung aufheben, wenn Sie nicht erneut benachrichtigt werden möchten.Was genau passiert, wenn ich innerhalb eines Lambda das Objekt lösche, das dieses Lambda enthält?

Das Problem, das ich habe, ist, dass ich lambdas registriert haben, dass auf aufgerufene wird Registrierung von diesem System die Zerstörung des aktuellen Lambda ausgeführt wird. Und ich denke, das ist nicht sicher. Aber ich bin mir nicht sicher.

Vereinfachen zum Beispiel:

#include <map> 
#include <functional> 
#include <iostream> 


int main() { 
    std::map<int, std::function<void()>> m; 
    m[10] = [&m]() { 
    int i = m.size(); // Just cheking the internal state of the lambda 
    m.clear(); 
    //i += m.size(); // If I uncomment this the std::cout is not working. 
    std::cout<< "What happens? " << i << std::endl; 
    }; 

    m[10](); 

    return 0; 
} 

Was ich sehe, ist, dass, wenn ich den Zustand des Lambda nach m.clear() überprüfen, ich seltsame Verhalten bekommen (zum Beispiel std::cout nicht funktioniert). Kannst du mir erklären, was genau in diesen Fällen passiert?

Wie werden Sie diese Situationen mit Rückrufen umgehen? vor dem Rückruf eine Kopie erstellen (scheint ein No-No)?

+0

Hier kann ich es reproduzieren: http://cpp.sh/2kjzg – FrameBuffer

Antwort

5

Denken Sie darüber nach, was passiert: Sie speichern eine Funktionsobjekt erzeugt mit einem Lambda-Ausdruck innerhalb eines std::function<void()>.

Die std::function jetzt besitzt die erzeugte Funktionsobjekt. Es befindet sich auch in einem std::map.

Sie erfassen dann das gleiche std::mapdurch Verweis und rufen std::map::clear darauf, die gespeicherte std::function entfernen.

Von der std::map::clear Dokumentation auf cppreference.org:

Entfernt alle Elemente aus dem Behälter. Macht alle Referenzen, Zeiger oder Iteratoren ungültig, die sich auf enthaltene Elemente beziehen. Jeder Iterator über die gesamte Laufzeit bleibt gültig.

Es ist sicher anzunehmen, dass clear ein std::map ing die in ihm gespeicherten Daten ungültig. Daher ist die Verwendung von Daten, die innerhalb des generierten Funktionsobjekts gespeichert sind, unsicher und könnte zu undefiniertem Verhalten führen.


Dies ist eine grobe Vereinfachung dessen, was Sie tun:

using func = std::function<void()>; 

func f; 
f = [&f]{ int a = 0; f.~func(); std::cout << a; }; 
Verwandte Themen