1. 基础理论
C++有了一套智能指针,为何UE要重新设计自己的呢?
(1)std::shared_ptr并不是所有平台通用。
(2)虚幻的智能指针可以与其他容器更好的协作,如TArray
。
(3)确保线程的安全与优化。
智能指针的原理: 使用引用计数,当引用计数为0时,会自动析构。
UE的智能指针的类型:
(1)TSharedPtr<class ObjectType, ESPMode Mode>:共享指针
(2)TSharedRef<class ObjectType, ESPMode Mode>:共享引用
(3)TWeakPtr<class ObjectType, ESPMode Mode>:弱指针
(4)TSharedFromThis<class OtherType, ESPMode OtherMode>:this智能指针
TSharedPtr与TSharedRef的区别: TSharedRef不能为空,这是唯一的区别
弱指针的作用:
(1)解决循环引用问题。
(2)不对资源的生命周期进行控制,只能使用资源,并不对资源进行竞争。比如:可以有线程专门管理资源的生命周期,而有些线程不关心资源的生命周期,只关心资源的使用问题,这时就可以使用弱指针只去使用这个资源。
(3)因为弱指针不管理生命周期,所以对其进行是否有效的判断是很有必要的。
2. TSharedPtr
/**
* TSharedPtr是一个宏,需要传入两个参数
* ObjectType:
* InMode:指明线程是否安全
*/
template< class ObjectType, ESPMode InMode >
class TSharedPtr
{
//.................
}
/** ESPMode的枚举 */
enum class ESPMode : uint8
{
// 线程不安全
NotThreadSafe = 0,
// 线程安全
ThreadSafe = 1,
// 灵活的Fast
Fast UE_DEPRECATED(5.0, "ESPMode::Fast has been deprecated - please use ESPMode::ThreadSafe instead") = 1
};
/** 提供的特化版本,默认使用ThreadSafe版本 */
template< class ObjectType, ESPMode Mode = ESPMode::ThreadSafe > class TSharedRef;
template< class ObjectType, ESPMode Mode = ESPMode::ThreadSafe > class TSharedPtr;
template< class ObjectType, ESPMode Mode = ESPMode::ThreadSafe > class TWeakPtr;
template< class ObjectType, ESPMode Mode = ESPMode::ThreadSafe > class TSharedFromThis;
创建:MakeShareable()
template< class ObjectType >
[[nodiscard]] FORCEINLINE SharedPointerInternals::TRawPtrProxy< ObjectType > MakeShareable( ObjectType* InObject )
{
return SharedPointerInternals::TRawPtrProxy< ObjectType >( InObject );
}
重载->
运算符,本质返回ObjectType*
,相当于返回我们共享指针指向对象的指针,我们就可以调用其所有的方法和变量了。
常用的函数如下:
/** 创建TSharedPtr */
TSharedPtr<FTestCppClass> TestSharedPtr = MakeShareable(new FTestCppClass());
/** 判断是否有效 */
if(TestSharedPtr.IsValid())
{
TestSharedPtr->TestFun();
}
/** 获取引用计数 */
int32 SharedPtrCount = TestSharedPtr.GetSharedReferenceCount();
/** 解引用,返回ObjectType* */
FTestCppClass* Test = TestSharedPtr.Get();
/** 将普通对象的所有权交给智能指针管理 */
FTestCppClass* TestCppClass = new FTestCppClass;
TSharedPtr<FTestCppClass> TestSharedPtr(MakeShareable(TestCppClass ));
/** Reset() 相当于 TestSharedPtr = nullptr */
TestSharedPtr.Reset();
/** Reset()源码 */
FORCEINLINE void Reset()
{
*this = TSharedPtr< ObjectType, Mode >();
}
3. TSharedRef
/** 创建共享引用 */
// 构造创建
TSharedRef<FTestCppClass> TestSharedRef(new FTestCppClass());
// 通过隐式转化创建
TSharedRef<FTestCppClass> TestSharedRef1 = MakeShareable(new FTestCppClass());
/** 获取引用计数 */
int32 SharedRefCount = TestSharedRef.GetSharedReferenceCount();
注意:TSharedRef不能置空,也就是必须有初始值,并且TSharedRef没有Reset()
4. TSharedPtr与TSharedRef的转化
/** 共享指针转化为共享引用 */
{
TSharedPtr<FTestCppClass> TestPtr = MakeShareable(new FTestCppClass);
TSharedRef<FTestCppClass> TestRef = TestPtr.ToSharedRef();
}
/** 共享引用转化为共享指针 */
{
TSharedRef<FTestCppClass> TestRef = MakeShareable(new FTestCppClass);
TSharedPtr<FTestCppClass> TestPtr = TestRef;
}
StaticCastSharedPtr/StaticCastSharedRef:父子级之间的转化
ConstCastSharedPtr/ConstCastSharedRef:将“常量”转化为“可变”的
/** 父子级之间的转化 */
{
TSharedPtr<FTestBaseClass> FatherPtr = MakeShareable(new FTestCppClass);
if(FatherPtr.IsValid())
{
// 将父类转化为子类
TSharedPtr<FTestCppClass> ChildrenPtr = StaticCastSharedPtr<FTestCppClass>(FatherPtr);
}
}
/** 将“常量”转化为“可变”的 */
{
const TSharedPtr<FTestBaseClass> FatherPtr = MakeShareable(new FTestBaseClass);
if(FatherPtr.IsValid())
{
// 将父类转化为子类
TSharedPtr<FTestBaseClass> ChildrenPtr = ConstCastSharedPtr<FTestBaseClass>(FatherPtr);
}
}
5. TWeakPtr
弱指针的作用和C++一致,通过引用计数不加1,用来解决智能指针的循环引用问题,这里不进行赘述…
6. TSharedFromThis
作用:继承自TSharedFromThis<class OtherType, ESPMode OtherMode>
的类,自带一个弱指针,可以将this作为智能指针进行传递或管理。
/** 传递this指针 */
class FTestCppClass;
class FTestBaseClass
{
public:
void TestFun(const TSharedPtr<FTestCppClass>& TestCppClass)
{
}
};
class FTestCppClass : public TSharedFromThis<FTestCppClass>
{
public:
void NotifyUpdate()
{
FTestBaseClass TestBaseClass;
// 将this指针当作智能指针进行传递
TestBaseClass.TestFun(this->AsShared());
}
};
/** 将继承自TSharedFromThis的类转化为智能指针 */
FTestCppClass* TestCppClass = new FTestCppClass;
TSharedPtr<FTestCppClass> TestSharedPtr = TestCppClass->AsShared();