Vorbei shared_ptr zu lambda-Wert von Speicherverlusten
Ich habe den folgenden code :
void MyClass::onOpenModalBtnClicked() {
uiManager->load(L"data/ui/testmodal.json");
std::shared_ptr<UIElement> modal = uiManager->getElementById("loginModal");
if(modal) {
modal->getElementById("closeButton")->onClicked = [modal]() {
modal->hide();
};
}
}
Dies funktioniert gut und der modal ist geschlossen, wenn die Schaltfläche geklickt wird, wird onClicked
ist ein std::function
.
Ich habe auch dieses am Anfang meiner app :
#if defined(DEBUG) | defined (_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
Dieser druckt Speicherverlusten, wenn die app beendet wird.
Mit dem obigen code erhalte ich viele Speicherlecks, wenn ich ändern Sie den code unten sind Sie alle Weg :
void MyClass::onOpenModalBtnClicked() {
uiManager->load(L"data/ui/testmodal.json");
std::shared_ptr<UIElement> modal = uiManager->getElementById("loginModal");
if(modal) {
modal->getElementById("closeButton")->onClicked = [this]() {
uiManager->getElementById("loginModal")->hide();
};
}
}
Ich gehe davon aus, dass die übergabe in der shared_ptr
von Wert erhöht den ref-count um 1 und dann dieser Verweis geht nie out of scope oder es geht out of scope, nachdem Sie die mem-leaks berichtet. Also ich habe versucht anzurufen, reset innerhalb des lambda-nachdem ich verwendet, shared_ptr, aber dann bekomme ich diese compiler-Fehlermeldung :
Error 1 error C2662: 'void std::shared_ptr<_Ty>::reset(void) throw()' : cannot convert 'this' pointer from 'const std::shared_ptr<_Ty>' to 'std::shared_ptr<_Ty> &'
Also die Frage ist, wie kann ich die aufgenommenen modal
und nicht diese memory-leaks?
Edit:
So vergraul ich die compile-Fehler durch hinzufügen mutable
zu lambda.
if(modal) {
modal->getElementById("closeButton")->onClicked = [modal]() mutable {
modal->hide();
modal.reset();
};
}
Nun, wenn ich auf die Schaltfläche schließen, schließen Sie die app, es gibt keine Speicher Lecks, da Sie die reset-reinigt, die Referenz. Aber wenn der button noch nie angeklickt, ich bekomme immer noch den undichten stellen.
- Sind Sie positiv, dass das Objekt, das festhalten an der onClicked zerstört wird, richtig? Gäbe es keine Möglichkeit zu zerstören, die
shared_ptr
bis onClicked zerstört wird. - Der Destruktor für die schließen-Schaltfläche wird nie aufgerufen, wenn ich capture
modal
eigentlich keiner von den Destruktoren werden aufgerufen, für alles, was ein Kind von modal. Das lässt mich glauben, dass die erfasstenmodal
geht nie out of scope. - Danke, das war das Stück, das ich war nicht zu sehen. Beantwortung von eingehenden.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie haben eine shared_ptr-Zyklus.
modal nicht zerstört werden kann, bis sein Verweiszähler 0 trifft. Sie übergeben dann eine Kopie des shared_ptr zu modal in der labmda Funktion, erhöht Ihren Verweiszähler. Ordnen Sie dann, dass die lambda-Funktion zu einem Mitglied der modal.
Dies bedeutet, dass die modal ist immer bezeichnet durch seine callback-Funktion. Jedoch, seine callback-Funktion kann nicht zerstört werden, bis modal hat keine refcount. Modal-enden stecken, mit einem ref-count von 1.
Die übliche Lösung ist vorbei, dass entweder eine Nackte Zeiger oder (bevorzugt) eine schwache Zeiger in die lambda -
Nicht.
Als Lösung für dieses problem habe ich folgenden einfachen test:
Woher bekomme ich das folgende Bild als Ausgabe:
Wie Sie sehen können, wenn Sie überschreiben onClick-handler destroy event aufgerufen wird. So gibt es keine Notwendigkeit für eine reset () - Aufrufe innerhalb lambda-Körper. Siehe Referenz-Zähler ausgegeben wird. Die lambda ist die functor-Objekt und wird richtig zerstört, wenn die Halter Objekt (modal im Beispiel) nicht mehr vorhanden oder das Feld ist deaktiviert (oder aktualisiert).