UE4 智能指针
为什么要用这个东西
主要是方便管理内存的释放,使用智能指针可以通过引用计数的方式方便的处理这些问题。
UE的智能指针来源于c++的智能指针,同时针对UE引擎的对接进行了封装,尤其是在TArray
里使用智能指针更便捷,高性能。
四种指针
基本结构
xxx<class OjectType, ESPMode Mode>
类型 | 名称 | 对应C++ |
---|---|---|
共享指针 | TSharedPtr | std::shared_ptr |
共享引用 | TSharedRef | std::shared_ref |
弱指针 | TWeakPtr | std::weak_ptr |
自带弱引用 | TSharedFromThis | std::enable_shared_from_this |
OjectType 对象类型
ESPMode 指针模式:更快
或线程安全
{
NotThreadSafe=0, // 最快
Fast=FORCE_THREADSAFE_SHAREDPTRS?1:0,// 用宏来控制
ThreadSafe=1 // 有多线程必用
}
在创建时,可以不填写ESPMode
,默认为ESPMode::Fast
。
创建共享指针
//创建共享指针
TSharedPtr<FTestClass> TestPtr = MakeShareable(new FTestClass);
// 是否有效
TestPtr.IsValid();
// 引用计数
TestPtr.GetSharedReferenceCount();
// 解引用
FTestClass* TestClass = TestPtr.Get();
// 手动释放()
// 只有共享指针释放功能,共享引用没有,因为引用不能为空,到少为1。
TestPtr = nullptr;
TestPtr.Reset();
//看引用是否唯一,用在类似单例的情况下
TestRef.IsUnique();
创建共享引用
❗ 注意: 引用不能为空
❗ 注意: 引用不能为空
❗ 注意: 引用不能为空
//创建共享引用 隐匿转换
TSharedRef<FTestClass> TestRef = MakeShareable(new FTestClass);
// 错误的共享引用创建,因为引用不能为空
// TSharedRef<FTestClass> TestRef;
// TSharedRef<FTestClass> TestRef = nullptr;
TestPtr.IsValid();// 是否有效
TestPtr.GetSharedReferenceCount();// 引用计数
FTestClass* TestClass = TestPtr.Get();// 解引用
TestRef.IsUnique();//是否唯一
// 不能手动释放
// 不能手动释放
// 不能手动释放
一个小知识点
c++ 在 new 的时候会生成一个对象指针
FTestClass* TestClass = new TestClass();
而new
也分两种
new TestClass();
new TestClass;
大部分情况没区别,只有一种情况有区别:
- new class 动态申请的空间里面的值是随机值
- new class() 进行了内置类型值的初始化,里面的值为0来
TSharedPtr与TSharedRef互相转换
// 引用 -> 指针 直接转,隐式转换
TSharedPtr<FTestClass> TestPtr2 = TestRef;
// 指针 -> 引用
TSharedRef<FTestClass> TestRef2 = TestPtr.ToSharedRef();
父子类转换
获取到一个对象,在统一处理时,会按基类(父类)来处理,但到某个时候想要转换成子类时,智能指针需要特殊转换。
如有父类
FParentClass
和子类FSonClass
// 父类转子类 需要调用方法
TSharedPtr<FParentClass> ParentPtr = MakeShareable(new FSonClass);
TSharedPtr<FSonClass> SonPtr = StaticCastSharedPtr<FSonClass> (ParentPtr);
if(SonPtr.IsValid())
{
// 如果转换成功就可以调用子类相关的函数
}
// 子类转父类 直接转换
// 引用同理
StaticCastSharedRef<>();
常量类型消除常量
有时对一个const
的对象进行智能指针封装,有时需要消除他的const
属性,来调用函数,可以如下。
TSharedPtr< const FBaseClass> ConstBaseClass = MakeShareable(new FBaseClass());
if (ConstBaseClass.IsValid())
{
ConstBaseClass->ConstBaseFun(); // ConstBaseFun为const函数
// ConstBaseClass->BaseFun(); // BaseFun为非const函数,错误,因为为const对象不能访问非const函数
TSharedPtr<FBaseClass> BaseClass = ConstCastSharedPtr<FBaseClass>(ConstBaseClass);
if (BaseClass.IsValid())
{
BaseClass->BaseFun();
}
}
// 引用同理
ConstCastSharedRef<>();
弱指针
在出现环形引用
的时候,如果都使用强指针,则永远不会销毁。
class FClassA:
{
public:
TSharedPtr<FClassB> ClassBRef;
}
class FClassB:
{
public:
TSharedPtr<FClassA> ClassARef;
}
当FClassA
里引用FClassB
,同理FClassB
也引用了FClassA
,此时他们的引用技术为都为1,即便不使用了,也不会变为0而销毁。
如何解决:
不管哪个类里,如在FClassA
中,把TSharedPtr<FClassB>
修改为TWeakPtr<FClassB>
,弱指针只保留引用,并不计数,所以就能解决这个问题。但也同时需要注意,有可能弱指针的引用无效,所以使用前都要很检查下。
常用用法:
- 弱指针不能影响指针的引用计数。
- 在使用弱指针时,需要对其进行检测,判断其是否有效。
- 弱指针最大的用途就是解决环形引用的问题。
- 弱指针另一个作用就是,不对资源进行竞争。只能使用资源,却没有权限控制资源的生命周期。
让类自带弱引用
我们在处理一个原生类时,如果原生类想与其他智能对象有交互,可能让这个原生类继承TSharedFromThis
,这样在使用这个对象时,可以自带智能指针。
class FTestClass : TSharedFromThis<FTestClass>
{}
FTestClass* TestClass = new FTestClass();
// 如果这时想当智能指针用,要么
TSharedPtr<FTestClass> TestPtr = MakeShareable(new FTestClass());
// 还可以这样
TestNormalPtr->AsShared();
这样可以灵活的使用智能指针。
其实最开始c++
的enable_shared_from_this
目的主要是使用在多线程中,比如Socket
通信时。
最后注意
UE的UObject
自带垃圾回收,使用的就是智能指针,所以,不能对UObject
再次使用智能指针。
评论