通过值将shared_ptr传递给lambda会导致内存泄漏 [英] Passing shared_ptr to lambda by value leaks memory
问题描述
我有以下代码:
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();
};
}
}
这很好用,并且单击按钮时模态是关闭的, onClicked
是 std :: function
.
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();
};
}
}
我假设按值传递 shared_ptr
会使ref计数增加1,然后此引用永远不会超出范围,或者在报告内存泄漏后不会超出范围.所以我尝试在使用shared_ptr之后在lambda内调用reset,但是随后出现此编译器错误:
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 :
错误1错误C2662:'void std :: shared_ptr< _Ty> :: reset(void)throw()':无法从'const std :: shared_ptr< _Ty>'转换'this'指针到'std :: shared_ptr< _Ty>&'
所以问题是我该如何使用捕获的 modal
而不出现那些内存泄漏?
So the question is how can I use the captured modal
and not get those memory leaks?
修改:因此,我通过向Lambda添加 mutable
摆脱了编译错误.
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.
推荐答案
您已创建了shared_ptr周期.
You have created a shared_ptr cycle.
modal必须在其引用计数达到0之前销毁.然后,将shared_ptr的副本传递给modal到labmda函数中,以增加其引用计数.然后,您将该lambda函数分配给modal成员.
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.
这意味着模式始终由其回调函数引用.但是,除非模式没有引用计数,否则无法销毁其回调函数.模态最终被卡在ref计数为1的地方.
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.
通常的解决方案是将裸指针或(最好是)弱指针传递到lambda中.
The usual solution is to pass either a naked pointer or (preferrably) a weak pointer into the lambda
这篇关于通过值将shared_ptr传递给lambda会导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!