I have the following 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();
};
}
}
This works fine and the modal is closed when the button is clicked, onClicked
is a std::function
.
I also have this at the beginning of my app :
#if defined(DEBUG) | defined (_DEBUG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
This prints out memory leaks when the app terminates.
With the above code I get lots of memory leaks, if I change the code to the below they are all gone :
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();
};
}
}
I am assuming passing in the shared_ptr
by value increases the ref count by 1 and then this reference never goes out of scope or it goes out of scope after the mem leaks are reported. So I tried to call reset inside the lambda after I used the shared_ptr but then I get this compiler error :
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> &'
So the question is how can I use the captured modal
and not get those memory leaks?
Edit:
So I got rid of the compile error by adding mutable
to the lambda.
if(modal) {
modal->getElementById("closeButton")->onClicked = [modal]() mutable {
modal->hide();
modal.reset();
};
}
Now if I click the close button, and close the app there are no memory leaks, since the reset cleans that reference. But if the button is never clicked I still get the leaks.
You have created a shared_ptr cycle.
modal cannot be destroyed until its reference count hits 0. You then pass a copy of a shared_ptr to modal into the labmda function, incrementing its reference count. You then assign that lambda function into a member of modal.
This means that modal is always referred to by its callback function. However, its callback function cannot be destroyed until modal has no refcount. Modal ends up getting stuck with a ref count of 1.
The usual solution is to pass either a naked pointer or (preferrably) a weak pointer into the lambda
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With