C++ – 在两个互有依赖关系的类中使用std::shared_ptr和std::weak_ptr进行内存管理
本文作者:StubbornHuang
版权声明:本文为站长原创文章,如果转载请注明原文链接!
原文标题:C++ – 在两个互有依赖关系的类中使用std::shared_ptr和std::weak_ptr进行内存管理
原文链接:https://www.stubbornhuang.com/2147/
发布于:2022年05月31日 17:08:46
修改于:2022年05月31日 17:24:30

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;
}
参考链接
当前分类随机文章推荐
- C++11/std::atomic - 原子变量(不加锁实现线程互斥) 阅读4495次,点赞2次
- C++ - 线程安全的std::cout 阅读1281次,点赞0次
- C++ - 格式化json字符串,方便展示json字符串的层次结构 阅读1130次,点赞0次
- C++STL容器 - std::map查找元素与判断键值是否存在方法总结 count,find,contains,equal_range,lower_bound,upper_bound 阅读426次,点赞0次
- C++ - 只有在Debug模式下才使用std::cout输出调试日志,Release发布版本不输出调试日志 阅读3033次,点赞0次
- C++ - 控制台程序在控制台窗口可变参数格式化带颜色输出日志信息 阅读2377次,点赞0次
- C++11 - 解析并获取可变参数模板中的所有参数 阅读662次,点赞0次
- C++11 - std::bind简要介绍以及可绑定函数的几种形式总结 阅读3619次,点赞3次
- C++ - C++类的特殊成员函数,析构函数,拷贝构造函数,移动构造函数,赋值运算符,移动赋值运算符介绍和基础语法 阅读350次,点赞0次
- C++ - C++使用cuda api获取当前GPU显卡的总共的显存容量、已使用显存容量、剩余显存容量 阅读1688次,点赞2次
全站随机文章推荐
- FFmpeg - ./configure编译参数全部总结和整理 阅读449次,点赞0次
- 资源分享 - High Dynamic Range Imaging- Acquisition, Display, and Image-Based Lighting ( First Edition )PDF下载 阅读2089次,点赞0次
- 资源分享 - GPU Pro 7 - Advanced Rendering Techniques 英文高清PDF下载 阅读1753次,点赞0次
- 资源分享 - Practical Augmented Reality - A Guide to the Technologies, Applications, and Human Factors for AR and VR-Addison 英文高清PDF下载 阅读872次,点赞0次
- 资源下载 - GPU Pro(1-7)英文原版高清PDF带书签下载 阅读9623次,点赞3次
- 资源分享 - Interactive Computer Graphics - A top-down approach with shader-based OpenGL(Six 6th Edition)英文高清PDF下载 阅读1698次,点赞0次
- 资源分享 - Graphics Programming Methods 英文高清PDF下载 阅读1323次,点赞0次
- 资源分享 - Practical Rendering and Computation with Direct3D 11 英文高清PDF下载 阅读1339次,点赞0次
- Duilib - 点击程序关闭按钮最小化到托盘,点击托盘按钮恢复 阅读1069次,点赞0次
- Pytorch - torch.stack参数详解与使用 阅读96次,点赞0次
评论
153