当前位置:网站首页>UE4 智能指针和弱指针
UE4 智能指针和弱指针
2022-07-26 14:03:00 【飞起的猪】
一、序言
我们知道C++里面有自己的指针,但是在虚幻引擎中原生C++的指针在分配和释放内存时会产生一些问题,比如无法被虚幻进行回收,造成内存泄漏等问题,于是虚幻就衍生出了智能指针。虚幻智能指针库是 C++11 智能指针的自定义实现,旨在减轻内存分配和跟踪的负担。此实现包括行业标准共享指针、弱指针和唯一指针。它还添加了类似于不可为空的共享指针的共享引用。这些类不能与UObject系统一起使用,因为虚幻对象使用单独的内存跟踪系统,该系统针对游戏代码进行了更好的调整。
二、各个指针的含义
共享指针(TSharedPrt):共享指针拥有它引用的对象,无限期地阻止删除该对象,并最终在没有共享指针或共享引用,引用它时处理它的删除。共享指针可以为空,这意味着它不引用任何对象。任何非空共享指针都可以生成对其引用的对象的共享引用。
共享引用(TSharedRef):共享引用的作用类似于共享指针,因为它拥有它所引用的对象。它们在空对象方面有所不同;共享引用必须始终引用非空对象。因为共享指针没有这个限制,所以共享引用总是可以转换为共享指针,并且共享指针保证引用一个有效的对象。当您想要保证被引用的对象是非空的,或者如果您想要指示共享对象的所有权时,请使用共享引用。
弱指针(TWeakPtr):弱指针类似于共享指针,但不拥有它们引用的对象,因此不会影响其生命周期。这个属性非常有用,因为它打破了引用循环,但这也意味着弱指针可以随时变为空,而不会发出警告。出于这个原因,弱指针可以生成指向它引用的对象的共享指针,从而确保程序员临时安全地访问该对象。
唯一指针(TUniquePtr):唯一指针单独且明确地拥有它所引用的对象。由于给定资源只能有一个唯一指针,因此唯一指针可以转移所有权,但不能共享它。任何复制唯一指针的尝试都将导致编译错误。当唯一指针超出范围时,它会自动删除它引用的对象。
三、指针的用法
为了更好的使用指针,虚幻提供了几个帮助类和函数,使使用智能指针更容易、更直观。
| 从 |
| 从常规 C++ 指针创建共享指针。 |
| 静态转换实用函数,通常用于向下转换为派生类型。 |
| 将 |
四、使用智能指针的优缺点
优点:
std::Shared_Ptr不是在所有的平台上都可用。
使得在所有的编译器和平台上更加一致性。
可以和其他虚幻容器无缝协作。
更好的控制平台特性,包括线程处理和优化。
线程安全的功能。
我们想在性能方面有更多的控制权(内敛函数,内存,虚函数等)。
在不需要的时候不需要引入第三方依赖。
缺点:
创建和复制智能指针比创建和复制原始 C++ 指针涉及更多开销。
维护引用计数会增加基本操作的周期。
一些智能指针比原始 C++ 指针使用更多内存。
参考控制器有两个堆分配。使用
MakeShared而不是MakeShareable避免第二次分配,并且可以提高性能。
五、案例测试
原生C++与智能指针之间的转化
创建一个C++ Actor类 命名为 MyActor
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
class TaskA
{
public:
int32 a;
float b;
};//创建一个原生的C++类
UCLASS()
class HEXINU4_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AMyActor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void TaskAA();//共享指针测试函数
void TaskSharedRef();//共享引用测试函数
void TaskSharedRefAndPtr();//共享指针和共享引用之间相互转化
void TaskweakPrt();//弱指针的测试函数
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
TSharedPtr<TaskA> Task_a;//共享指针可以为 NULL 但是不可以复制,使用共享指针最好全局指针,不要创建临时指针好它比普通的指针耗资源
};
// TSharedRef<TaskA> Task_b;//不能这么声明共享引用是错误的
TWeakPrt<TaskA> Task_c;//弱指针的声明
void AMyActor::TaskAA()
{
Task_a= MakeShareable(new TaskA());//共享指针创建一个智能指针
if (Task_a.IsValid() || Task_a.Get())//判断共享指针是否有效或者解引用
{
Task_a.Get()->a;//可替换为Task_a->a;
Task_a.Reset();
}
}
void AMyActor::TaskSharedRef()
{
TSharedRef<TaskA> Task_b(new TaskA());//共享引用必须初始化可用对象
Task_b->a;
}
void AMyActor::TaskSharedRefAndPtr()
{
//共享引用转化成共享指针
TSharedRef<TaskA> Task_b(new TaskA());
Task_a = Task_b;
//普通指针转化成共享指针
TaskA *NewTaskA = new TaskA();
Task_a = MakeShareable(new NewTaskA);
//注意
// Task_b = nullptr;//错误的
Task_b = Task_a.ToSharedRef();//共享指针转换成共享引用是不安全的它有个断言
}
void AMyActor::TaskweakPrt()
{
TSharedPtr<TaskA> _TaskA_ptr = MakeShareable(new TaskA());//共享指针
TSharedRef<TaskA> _TaskA_ref(new TaskA());//共享引用
TweakPtr<TaskA>Task_D(_TaskA_ptr);
TweakPtr<TaskA>Task_K(_TaskA_ref);
Task_c = Task_D;
Task_c = Task_K;
Task_c = nullptr;//防止对象被销毁
//弱指针转化成智能指针
TSharedPtr<TaskA> NewTask(Task_c.Pin());
if(NewTask.IsValid())
{
NewTask->a;
}
}智能指针之间的转化
class FBase
{
public:
protected:
private:
};
class FB : public FBase
{
public:
void Printf() {};
protected:
private:
};
//将基类转化成派生类,访问派生类的函数和变量
TSharedPtr<FBase> B_ = MakeShareable(new FB());//共享指针和UObject不兼容,UObject有自己的销毁机制
TSharedPtr<FB> C_ = StaticCastSharedPtr<FB>(B_);
if (C_.IsValid())
{
C_->Printf();
}
const TSharedPtr<FBase> E_ = MakeShareable(new FB());
TSharedPtr<FBase> D_ = ConstCastSharedPtr<FBase>(E_);
TSharedPtr<FB> F_ = StaticCastSharedPtr<FB>(D_);
if (F_.IsValid())
{
F_->Printf();
}TSharedFromThis()的用法:保留一个对对对象的弱引用,方便直接转化成共享引用AsShared();
class TaskA:public TSharedFromThis<TaskA>
{
public:
int32 a;
float b;
};
.CPP文件中测试
TSharedPtr<TaskA>NewTest = MakeShareable(new TaskA());
newtask->a;
TaskA *NewTest1 = NewTest.Get();//解引用将智能指针转化成原生指针
if (NewTest1)
{
NewTest1->AsShared();
}
TaskA *currentTask = new TaskA();//原生指针
TSharedRef<TaskA> Task_c = currentTask->AsShared();综合案例
#include "CoreMinimal.h"//
class IMyID//一个用户ID类
{
public:
IMyID()
{
ID = FMath::RandRange(100, 1000);
}
FORCEINLINE uint64 GetID() { return ID; }//强制内敛ID
private:
int32 ID;
};
class FData:public IMyID//数据继承ID类,有自己的数据参数
{
public:
FData()
{
Health = 100.f;
bDeath = 0;
PlayerName = TEXT("CharacterOne");
}
float Health;
uint8 bDeath;
FName PlayerName;
};
class FDataManager//数据管理类
{
public:
static TSharedRef<FDataManager> Get()
{
if (DataMager.IsValid())
{
DataMager = MakeShareable(new FDataManager());
}
return DataMager.ToSharedRef();
}
TSharedRef<FData> CreatData()
{
TSharedPtr<FData> tmp_Data = MakeShareable(new FData());
MyData.Add(tmp_Data->GetID(), tmp_Data);
return tmp_Data.ToSharedRef();
}
~FDataManager()
{
}
private:
static TSharedPtr<FDataManager> DataMager;
TMap<uint64, TSharedPtr<FData>> MyData;
};
//角色实例显示
class FCharacter
{
public:
FORCEINLINE bool IsValid()
{
return NewData.IsValid();
}
void SetNewData(TSharedRef<FData> CurrentNewData) { NewData = CurrentNewData; }
void SetNewName( FString NewName)
{
if (NewData.IsValid())
{
NewData.Pin()->PlayerName = FName(*NewName);
}
}
FORCEINLINE bool IsValid() { return NewData.IsValid(); }
protected:
private:
TWeakPtr<FData> NewData;//弱指针不参与类的生命周期
};
void NewMain()//假设是一个场景
{
FCharacter* Character = new FCharacter();
Character->SetNewData(FDataManager::Get()->CreatData());
Character->SetNewName("PlayerTwo");
}
//注意如果是一个裸指针(C++原生指针)当删除这个指针时会崩溃,产生野指针,解决方法是加上一个TSharedFromThis(FData),让它始终被一个弱指针包裹
class FData:public IMyID,public TSharedFromThis(FData)//数据继承ID类,有自己的数据参数
{
public:
FData()
{
Health = 100.f;
bDeath = 0;
PlayerName = TEXT("CharacterOne");
}
float Health;
uint8 bDeath;
FName PlayerName;
};
FData* CreatData()
{
TSharedPtr<FData> tmp_Data = MakeShareable(new FData());
MyData.Add(tmp_Data->GetID(), tmp_Data);
return tmp_Data.Get();
}
void NewMain()//假设是一个场景
{
FCharacter* Character = new FCharacter();
FData* New_Data = FDataManager::Get()->CreatData();
Character->SetNewData(New_Data->AsShared());
Character->SetNewName("PlayerTwo");
}
边栏推荐
- C语言_结构体指针来访问结构体数组
- 多态案例-制作饮品
- MLX90640 红外热成像仪测温传感器模块开发笔记(六)
- Understand the meaning of length in MySQL data types
- [paper reading] raw+:a two view graph propagation method with word coupling for readability assessment
- 基于用户画像的在线健康社区用户流失预测研究
- Plato Farm有望通过Elephant Swap,进一步向外拓展生态
- C语言_结构体和数组的结合
- Force deduction ----- the number of words in the string
- Mobile dual finger scaling event (native), e.originalevent.touches
猜你喜欢

android安全基础知识学习

.net6与英雄联盟邂逅之——根据官方LCU API制作游戏助手

基于多特征的技术融合关系预测及其价值评估

Pytorch学习笔记(二)神经网络的使用

The difference between V-model and.Sync modifier

Docker container MySQL enables binlog and scheduled backup

天翼云Web应用防火墙(边缘云版)支持检测和拦截Apache Spark shell命令注入漏洞

基于SPO语义三元组的疾病知识发现

Focus on building four "highlands" and join hands with partners to build the national cloud!
![[GYCTF2020]FlaskApp](/img/ee/dcb42617af4a0e41657f6cf7095feb.png)
[GYCTF2020]FlaskApp
随机推荐
JS page turning, kkpager.js page turning
ROS2学习(1)ROS2简述
421. Maximum XOR value of two numbers in the array
Share 44 JS problems, and half of them are masters
mysql5.7通过文件zip方式安装-九五小庞
JS, e.pagex, pagey modal box drag
[GYCTF2020]FlaskApp
Pytoch learning notes (I) installation and use of common functions
Native JS get transform value x y z and rotate rotation angle
Intercept the coordinate points (four point coordinates of the face frame) face image from the marked XML file and save it in the specified folder
gdb常用命令
基于用户画像的在线健康社区用户流失预测研究
MySql的DDL和DML和DQL的基本语法
Polymorphic case - making drinks
Upload pictures to get width and height
Explain four interesting NPM usages with charts
Red * is added to the input box to indicate mandatory items
多态案例-制作饮品
Re bet overseas: Alibaba, jd.com and SF again fight for "internal power"
Force deduction ----- the number of words in the string