Unreal Engine:动态内存和智能指针
0. 为什么需要使用动态内存?
- 不知道自己需要使用多少对象 —— 容器类
- 不知道所需对象的准确类型
- 需要在多个对象间共享数据 —— shared_ptr
1. 为什么要用智能指针?
内存泄漏:野指针崩溃。
内存溢出:忘记删除,占用内存。
UE里,UObject类会在引擎关闭时自动释放资源,那么没有继承自UObject的类呢?就用智能指针来管理。
2. 智能指针优缺点?
- 防止内存泄露
- 包含“线程安全” 版本:可以通过多线程安全的进行访问,可跨线程管理引用计数。
- 运行时安全:共享引用从不为空,可固定随时取消引用。
- 授予意图:可轻松区分对象所有者和观察者。
- 可以创建任何类型的对象的共享指针。
- 支持复制、解引用、比较、const、前置声明的不完全类型、类型转换等。
3. C++里的智能指针
智能指针也是模板。
unique_ptr
建议初始化方式:unique_ptr<int> sp = make_unique<int>(123);
引用计数永远为1。为了防止复制和赋值,unique_ptr的拷贝构造函数和赋值运算符都被标记为delete。要想指向的堆内存转移给别人,只能使用移动构造。
移动构造:
sp2 = std::move(sp1);
通常被用来初始化另一个智能指针:p2.reset(p1.release());
shared_ptr
建议初始化方式:shared_ptr<int> sp = make_shared<int>(123);
每多一个引用,引用计数+1,每析构一个对象,引用计数-1。引用计数为0,释放资源。
use_count() :获取当前引用计数(慢,用于调试)
shared_ptr<T> p(q) :p是q的拷贝,会增加q的引用计数。
unique() :use_count() 返回1时为true
当引用计数不为0时,调用析构函数,会出现如下结果:
优化:shared_ptr存放于一个容器中时,erase删掉不再需要的shared_ptr元素。
-----------通用操作-------------
swap(p,q) <=> p.swap(q) 交换指针
*p 解引用,获得指向对象
p->mem
-------------------------------------
weak_ptr
不控制所指向对象生存周期。
弱引用,指向shared_ptr所管理的对象,不增加shared_ptr的引用计数。
可用来解决shared_ptr相互引用造成的死锁问题。
初始化方式:
通过构造函数:weak_ptr<int> sp2(sp1); //sp1是shared_ptr对象
通过赋值运算符:weak_ptr<int> sp3 = sp1;
通过weak_ptr:weak_ptr<int> sp4 = sp3;
如何得知其引用对象是否存在?expired() true:不存在
weak_ptr不能直接对资源进行操作,因为没有重写一些运算符方法,
判断对象是否存在之后, if(wp.expired()) return;
用lock()得到一个shared_ptr,继续对对象操作,shared_ptr<int> sp = wp.lock();
-----------------Unreal Engine-------------
TSharedPtr:不能指向UObject。想要只想UObject,可以用TWeakObjectPtr。可以对FStructures使用。
TSharedRef:不可为空,所以也没有IsValid()函数。
TWeakPtr:不参与引用计数;不存在共享指针时,自动失效;使用时先判断有效性。
TUniquePtr:只能被唯一指向,因此不能被赋值给其他指针。
============类 型 转 换=============
TSharedPtr转TSharedRef:sharedPtr.ToSharedRef();
派生类转基类:直接转。
基类转派生类:StaticCastSharedPtr
常量指针转非常量指针:ConstCastSharedPtr
==============智能指针的大小===============
____________________________________
参考:https://www.bbsmax.com/A/xl56YWO0Jr/
https://www.zhihu.com/question/319277442/answer/1517987598
《C++ Primer》