一、基本概念
在UE4中,继承UObject的类被实例化的对象在内存中可以被UE4的垃圾回收机制管理,从而不用担心内存泄漏等问题。但非继承UObject的普通C++类或结构体则需要被开发者管理,如果管理不善,很容易导致内存泄漏、野指针和程序崩溃等问题。对此,我们可以使用UE4提供的共享指针来创建和管理这些类对象。C++的stl库中也提供了一套智能指针系统来管理内存,但UE4的共享指针比stl库提供的智能指针相比具有以下优势:
- 跨平台
- 与UE4引擎容器协调工作
- 针对平台的优化,如多线程等
UE4提供的共享指针主要有以下类型:TSharedPtr、TSharedRef、TWeakPtr、TUniquePtr。下面将一一介绍它们的用法。
二、UE4智能指针
1. TSharedPtr
使用共享指针创建对象:
TSharedPtr<TestStruct> StructPtr = MakeShareable(new TestStruct());
当使用共享指针时,为保证指针有效,可以使用IsValid判断指针的有效性:
if(StructPtr.IsValid())
{
StructPtr->Name = "Alter Name";
}
获取普通指针:
StructPtr.Get();
重置指针:
StructPtr.Reset();
判断是否唯一:
StructPtr.IsUnique();
获取引用次数:
StructPtr.GetSharedReferenceCount();
如果共享指针对象离开所在作用域或者当作为类成员变量时,类示例对象析构时,会自动处理共享指针的计数,不需要手动重置。因为在对象析构时,会执行成员变量的析构方法,而共享指针中包含一个用于计数的对象,当共享指针析构时,会调用计数对象的析构方法。
2. TSharedRef
TSharedRef的用法与TSharedPtr大致相似,但与TSharedPtr相比,共享引用更加安全。因为引用不能为空,且无法置空,共享引用的初始化一般通过MakeShared或共享指针的ToSharedRef函数赋值,所以更加安全。一般在函数参数传递和作为返回值时使用,共享引用没有提供IsValid进行有效性判断,如果要判断有效性,可通过Get获取原生指针。
创建共享引用:
TSharedRef<TestStruct> StructRef = MakeShared<TestStruct>(new TestStruct());
共享指针转共享引用:
TSharedPtr<TestStruct> StructPtr = MakeShareable(new TestStruct());
TSharedRef<TestStruct> StructRef = StructPtr.ToSharedRef();
共享引用转共享指针可以直接赋值转换:
TSharedRef<TestStruct> StructRef = MakeShared<TestStruct>(new TestStruct());
TSharedPtr<TestStruct> StructPtr = StructRef;
3. TWeakPtr
TWeakPtr指针与TSharedPtr相比,不参与引用计数。而当TWeakPtr指向的对象不存在共享指针指向时,TWeakPtr将自动失效,所以在使用弱指针时,需要进行有效性判断。
初始化TWeakPtr:
TSharedPtr<TestStruct> StructPtr = MakeShareable(new TestStruct());
TWeakPtr<TestStruct> StructWeakPtr(StructPtr);
使用时,进行有效性判断:
if(StructWeakPtr.IsValid())
{
StructPtr->Name = "Alter Name";
}
弱指针的Pin函数将会返回一个智能指针,所以弱指针转共享指针为:
TSharedPtr<TestStruct> StructPtr = MakeShareable(new TestStruct());
TWeakPtr<TestStruct> StructWeakPtr(StructPtr);
TSharedPtr<TestStruct> StructPtr2(StructWeakPtr.Pin());
4. TUniquePtr
唯一指针指向的对象只能被唯一指向,所以Unique指针不能赋值给其它指针。
创建TUniquePtr指针:
TUniquePtr<TestStruct> StructPtr = MakeUnique<TestStruct>(new TestStruct());
TUniquePtr指针还提供IsValid有效性判断和Reset重置函数。
5. TSharedFromThis
TSharedFromThis是一个模板类,普通C++函数继承TSharedFromThis类后,类将会保存一个弱指针,当通过智能指针获取到该类的普通指针时,可以通过调用AsShared方法获取到该类的智能指针。简而言之,继承该类的普通C++类可以将智能指针获得的普通指针再转为智能指针。
class FTestClass : TSharedFromThis<FTestClass>
{}
TSharedPtr<FTestClass> TestPtr = MakeShareable(new FTestClass());
FTestClass* TestNormalPtr = TestPtr.Get();
TSharedPtr<FTestClass> TestPtr2 = TestNormalPtr->AsShared();
注意:只有通过智能指针获取的普通指针才能使用AsShared转换为智能指针,否则可能崩溃。因为通过MakeShareable创建智能指针时,才会初始化其弱指针。