C++ – 在两个互有依赖关系的类中使用std::shared_ptr和std::weak_ptr进行内存管理
1 C++关于使用std::shared_ptr和std::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_ptr
的lock()
方法获取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
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论
52