初识共享指针与共享引用
UE4对于不继承UObject的类提供了一系列转换模板类与接口方法,十分方便,能够为自己的原生类进行垃圾回收,不用太担心野指针等恶性问题。
对于原生类,需要继承TSharedFromThis<T>来实现AsShared()方法。
class TaskA:public TSharedFromThis<TaskA>
{
public:
int32 a=155;
float b;
//单例,也是TSharedFromThis派生类的运用
static TSharedRef<TaskA> Get() {
if (m_Task_a.IsValid() || m_Task_a.Get())
{
//new一个类,然后将该类转换为共享指针并赋值给静态变量
m_Task_a = MakeShareable(new TaskA());
}
//转换为引用并返回
return m_Task_a->AsShared();
}
private:
static TSharedPtr<TaskA> m_Task_a;
};
void ATaskActor::TestAA()
{
Task_a = MakeShareable(new TaskA());
if (Task_a.IsValid() || Task_a.Get())
{
int32 temp = Task_a->a;
GEngine->AddOnScreenDebugMessage(-1, 50.0f, FColor::Red, FString::FromInt(temp));
Task_a.Reset();
}
}
void ATaskActor::TaskShareRef()
{
//共享引用
TSharedRef<TaskA> Task_b(new TaskA());
Task_b->a;
(*Task_b).a;
}
TSharedPtr<TaskA> TaskA::m_Task_a;
void ATaskActor::TaskRefAndPtr()
{
//将共享引用转换为共享指针
TSharedRef<TaskA> Task_c(new TaskA());
Task_a = Task_c;
//将普通指针转换为共享指针
TaskA* tempa = new TaskA();
Task_a = MakeShareable(tempa);
//将共享指针转换为共享引用
if (Task_a.IsValid() && Task_a.Get())
{
Task_c = Task_a.ToSharedRef();
}
//将普通指针变成共享引用,在类继承了TSharedFromThis后,就可以通过AsShared()获得引用。
TaskA* currentTaskA = new TaskA();
TSharedRef<TaskA> CurrentRefTaskA = currentTaskA->AsShared();
CurrentRefTaskA->a;
//声明完类里的私有变量后,才能使单例运作
TaskA::Get()->a;
}
弱指针
一般共享指针,在引用为0或者置空后,会被销毁,但是弱指针不会,对象依旧存在
class FTreeNode
{
//树结构,反正就是利用弱指针置空后不会销毁的机制
TArray<TSharedPtr<FTreeNode>> Children_;
TWeakPtr<FTreeNode> Parent_;
};
void ATaskActor::TaskWeakPtr()
{
TWeakPtr<TaskA> Task_E;
TSharedPtr<TaskA> _TaskA_ptr = MakeShareable(new TaskA());
TSharedRef<TaskA> _TaskA_Ref(new Task());
//创建
TWeakPtr<TaskA> Task_D(_TaskA_ptr);
TWeakPtr<TaskA> Task_K(_TaskA_Ref);
//转换,共享指针->弱指针
Task_E = Task_D;
Task_E = Task_K;
//使用完弱指针后重置
Task_E = nullptr;
//弱指针->共享指针
TSharedPtr<TaskA> NewTask(Task_E.Pin());
if (NewTask.Get())
{
NewTask->a;
}
}
智能指针的优缺点




强引用与弱引用
在智能指针的项目应用中,主要是可以让弱引用和强引用通信,并使强引用不会变成野指针
1 class IMyID { 2 IMyID() { 3 _id = FMath::RandRange(100, 10000); 4 } 5 FORCEINLINE uint64 GetID() { return _id; } 6 private: 7 uint64 _id; 8 }; 9 //数据 10 class FData :public IMyID ,TSharedFromThis<FData> 11 { 12 public: 13 FData() 14 { 15 _health = 100.0f; 16 bDeath = 0; 17 PlayerName = TEXT("yuyang"); 18 }; 19 public: 20 float _health; 21 uint8 bDeath : 1; 22 FName PlayerName; 23 }; 24 25 //数据管理 26 class FDataManager { 27 public:
//单例 28 static TSharedRef<FDataManager> Get() 29 { 30 if (!_DataManager.IsValid()) 31 { 32 _DataManager = MakeShareable(new FDataManager()); 33 } 34 return _DataManager.ToSharedRef(); 35 } 36 42 //内部添加字典元素,保存强引用,外部调用接口 43 TSharedRef<FData> CreateData() 44 { 45 TSharedPtr<FData> _data = MakeShareable(new FData()); 46 _MyDatas.Add(_data->GetID(), _data); 47 return _data.ToSharedRef(); 48 } 49 50 private: 51 static TSharedPtr<FDataManager> _DataManager; 52 53 TMap<uint64, TSharedPtr<FData>> _MyDatas; 54 55 56 }; 57 58 59 class FCharacter { 60 61 public: 62 63 //弱引用 64 void SetNewData(TSharedRef<FData> CurrentNewData) { 65 _Data = CurrentNewData; 66 } 67 void SetNewName(FString NewName) { 68 if (IsValid()) 69 { 70 _Data.Pin()->PlayerName = NewName; 71 } 72 } 73 74 FORCEINLINE bool IsValid() { 75 return _Data.IsValid(); 76 } 77 private: 78 TWeakPtr<FData> _Data; 79 }; 80 81 //假设一个场景 82 void m_NewMain() { 83 FCharacter* _FCharacter = new FCharacter();89 _FCharacter->SetNewData(FDataManager::Get()->CreateData()); 90 _FCharacter->SetNewName("杨涛"); 91 }
暴露指针注意事项
一般来说不推荐直接暴露指针给用户,很危险,动不动就野了
//数据 class FData :public IMyID ,TSharedFromThis<FData> { public: FData() { _health = 100.0f; bDeath = 0; PlayerName = TEXT("yuyang"); }; public: float _health; uint8 bDeath : 1; FName PlayerName; };
class FDataManager { public: FData* CreateDataNoProtect() { TSharedPtr<FData> _data = MakeShareable(new FData()); _MyDatas02.Add(_data->GetID(), _data); return _data.Get(); } private: TMap<uint64, FData*> _MyDatas02; };
在暴露指针的同时,如果又new了强指针指向这块数据的话,就会出现野指针。
一般来说,是打包成智能引用,或者不直接暴露。
//假设一个场景 void m_NewMain() { FCharacter* _FCharacter = new FCharacter(); { FData* _datanoprotect = FDataManager::Get()->CreateDataNoProtect(); _FCharacter->SetNewData(_datanoprotect->AsShared()); }; _FCharacter->SetNewData(FDataManager::Get()->CreateData()); _FCharacter->SetNewName("杨涛"); }
在将全局变量在函数里进行操作时,最好用new一个指针来赋值,这样不会随着离开作用域析构的时候导致野指针。

×

√
另外,不支持C++原生的转换方式。

浙公网安备 33010602011771号