• 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

  • 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

C++ – 在两个互有依赖关系的类中使用std::shared_ptr和std::weak_ptr进行内存管理

C++ 发布于2022-05-31 阅读 3,091次 0次评论 0次点赞 本文共2980个字,阅读需要8分钟。

1 C++关于使用std::shared_ptrstd::weak_ptr在两个互有依赖关系的类中的设计

先说一下需求场景,比如我现在需要写一个图形学渲染器,一个渲染器中可能包含多个渲染场景Scene类,每个Scene类又包含了多个需要渲染的模型Actor类,现在我在每个Scene里面通过维护一个std::vector<std::shared_ptr<Actor>>的容器用于管理加载到当前Scene中的所有Actor,而每一个Actor类也需要维护一个指向加载其模型的Scene类,用于后续归属关系判断以及调用当前Scene类中的成员函数,比如获取当前场景Scene中所使用灯光等,那么我们该如何设计一个模式在保证内存安全的情况下实现上述需求呢?

1.1 极易出现问题的代码

如果对C++智能指针使用不熟悉,很可能会写出下面有问题的代码。在Scene类中使用std::vector<std::shared_ptr<Actor>>保存添加的Actor共享智能指针,然后在Actor类中同样使用std::shared_ptr<Scene>保存Scene共享智能指针,这种情况就是典型的循环引用问题,造成内存泄漏。

示例代码:

#include <iostream>
#include <memory>
#include <vector>

#include <vld.h>

class Actor;
class Scene
{
public:
    Scene()
    {

    }

    virtual~ Scene()
    {
        std::cout << "Scene destruct" << std::endl;
    }

    void AddActor(std::shared_ptr<Actor> p_actor)
    {
        m_pActorVec.emplace_back(p_actor);
    }

    std::shared_ptr<Actor> GetActor(int index)
    {
        return m_pActorVec[index];
    }

    int GetActorNum()
    {
        return m_pActorVec.size();
    }

private:
    std::vector<std::shared_ptr<Actor>> m_pActorVec;
};

class Actor
{
public:
    Actor()
    {

    }

    Actor(std::shared_ptr<Scene> p_scene)
    {
        m_pScene = p_scene;
    }

    virtual~Actor()
    {
        std::cout << "Actor destruct" << std::endl;
    }

    std::shared_ptr<Scene> GetScene()
    {
        return m_pScene;
    }


private:
    std::shared_ptr<Scene> m_pScene;
};


int main()
{
    std::shared_ptr<Scene> p_scene = std::make_shared<Scene>();

    for (int i = 0; i < 10; i++)
    {
        std::shared_ptr<Actor> p_actor = std::make_shared<Actor>(p_scene);
        p_scene->AddActor(p_actor);
    }

    std::cout << "p_scene.use_count = " << p_scene.use_count() << std::endl;

    if (p_scene->GetActor(0)->GetScene() != nullptr)
    {
        auto temp_scene = p_scene->GetActor(0)->GetScene();
        if (temp_scene != nullptr)
        {
            std::cout <<"ActorNum = " << temp_scene->GetActorNum() << std::endl;
        }
    }

    return 0;
}

1.2 循环引用问题修改

1.1节中出现的循环引用问题,我们可以通过在Actor类中使用std::weak_ptr<Scene>保存Scene的共享智能指针进行解决。

在这里需要注意的是,由于在Actor类中使用std::weak_ptr<Scene>保存Scene的共享智能指针,如果我们直接使用std::weak_ptr型的智能指针调用Scene中的成员方法是没有办法成功的,这个使用需要使用std::weak_ptrlock()方法获取Scene中被管理的Shared_ptr对象,然后再调用Scene类中的成员方法。

详细的改动如下:

#include <iostream>
#include <memory>
#include <vector>

class Actor;
class Scene
{
public:
    Scene()
    {

    }

    virtual~ Scene()
    {
        std::cout << "Scene destruct" << std::endl;
    }

    void AddActor(std::shared_ptr<Actor> p_actor)
    {
        m_pActorVec.emplace_back(p_actor);
    }

    std::shared_ptr<Actor> GetActor(int index)
    {
        return m_pActorVec[index];
    }

    int GetActorNum()
    {
        return m_pActorVec.size();
    }

private:
    std::vector<std::shared_ptr<Actor>> m_pActorVec;
};

class Actor
{
public:
    Actor()
    {

    }

    Actor(std::shared_ptr<Scene> p_scene)
    {
        m_pScene = p_scene;
    }

    virtual~Actor()
    {
        std::cout << "Actor destruct" << std::endl;
    }

    std::shared_ptr<Scene> GetScene()
    {
        if (m_pScene.expired())
            return nullptr;

        return m_pScene.lock();
    }


private:
    std::weak_ptr<Scene> m_pScene;
};


int main()
{
    std::shared_ptr<Scene> p_scene = std::make_shared<Scene>();

    for (int i = 0; i < 10; i++)
    {
        std::shared_ptr<Actor> p_actor = std::make_shared<Actor>(p_scene);
        p_scene->AddActor(p_actor);
    }

    std::cout << "p_scene.use_count = " << p_scene.use_count() << std::endl;

    if (p_scene->GetActor(0)->GetScene() != nullptr)
    {
        auto temp_scene = p_scene->GetActor(0)->GetScene();
        if (temp_scene != nullptr)
        {
            std::cout <<"ActorNum = " << temp_scene->GetActorNum() << std::endl;
        }
    }

    return 0;
}

参考链接

欢迎扫码关注我的微信公众号,及时获取文章更新

微信公众号二维码

本文作者:StubbornHuang

版权声明:本文为站长原创文章,如果转载请注明原文链接!

原文标题:C++ – 在两个互有依赖关系的类中使用std::shared_ptr和std::weak_ptr进行内存管理

原文链接:https://www.stubbornhuang.com/2147/

发布于:2022年05月31日 17:08:46

修改于:2023年06月26日 20:03:21

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
C++ - 使用模板和智能指针构建一个双向链表工具类
C++
下一篇
计算机图形学 - Flat Shading、Gouraud Shading、Phong Shading的区别
计算机图形学
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号