加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 通过值将shared_ptr传递给lambda泄漏内存

发布时间:2020-12-16 03:15:46 所属栏目:百科 来源:网络整理
导读:我有以下代码: void MyClass::onOpenModalBtnClicked(){ uiManager-load(L"data/ui/testmodal.json"); std::shared_ptrUIElement modal = uiManager-getElementById("loginModal"); if(modal) { modal-getElementById("closeButton")-onClicked = [modal]()
我有以下代码:
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 ::函数.

我也在我的应用程序的开头有这个:

#if defined(DEBUG) | defined (_DEBUG)
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

这会在应用程序终止时打印出内存泄漏.

使用上面的代码,我会收到很多内存泄漏,如果我将代码更改为下面的代码,它们都会消失:

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通过值将引用计数增加1,然后该引用永远不会超出范围,或者在报告了mem泄漏之后超出范围.所以我试图在我使用shared_ptr之后调用lambda里面的reset,但是我得到这个编译器的错误:

错误1错误C2662:’void std :: shared_ptr< _Ty> :: reset(void)throw()’:不能将’this’指针从’const std :: shared_ptr< _Ty&gt到'std :: shared_ptr< _Ty> &安培;”

所以问题是如何使用捕获的模态,而不是得到那些内存泄漏?

编辑:
所以我通过向lambda添加mutable来摆脱编译错误.

if(modal)
{
    modal->getElementById("closeButton")->onClicked = [modal]() mutable {
        modal->hide();
        modal.reset();
    };
}

现在如果我点击关闭按钮,并关闭应用程序没有内存泄漏,因为重置清理该引用.但如果按钮从未点击,我仍然会收到泄漏.

解决方法

您已经创建了一个shared_ptr循环.

在引用计数命中0之前,模态不能被破坏.然后,将shared_ptr的副本传递给模态到labmda函数中,增加其引用计数.然后,您将该lambda函数分配给模态的成员.

这意味着模态总是由其回调函数引用.但是,它的回调函数在modal没有refcount之前不能被销毁. Modal最终以1的ref计数卡住.

通常的解决方案是将一个裸指针或(最好是)一个弱指针传给lambda

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读