当前位置:网站首页>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");
}
边栏推荐
- Plato Farm有望通过Elephant Swap,进一步向外拓展生态
- Understand the meaning of length in MySQL data types
- "Intermediate and advanced test questions": what is the implementation principle of mvcc?
- With frequent data leakage and deletion events, how should enterprises build a security defense line?
- Explain four interesting NPM usages with charts
- I. creation and constraint of MySQL table
- 周伟:寻找非共识性投资机会,陪伴延迟满足的创始团队
- [oauth2] VIII. Configuration logic of oauth2 login -oauth2loginconfigurer and oauth2clientconfigurer
- 循环队列(c语言实现)
- C language_ Structure pointer to access structure array
猜你喜欢

融合多自然语言处理任务的中医辅助诊疗方案研究——以糖尿病为例

Solve the problem that JUnit of idea console cannot be input with scanner

Plato Farm有望通过Elephant Swap,进一步向外拓展生态

Use the requests library to crawl web pages

【黑马早报】字节旗下多款APP下架;三只松鼠脱氧剂泄露致孕妇误食;CBA公司向B站索赔4.06亿;马斯克否认与谷歌创始人妻子有婚外情...

LCL三相pwm整流器(逆变器)

Comparison between agile development and Devops

redis学习笔记

"Intermediate and advanced test questions": what is the implementation principle of mvcc?
![[dark horse morning post] many apps under bytek have been taken off the shelves; The leakage of deoxidizer in three squirrels caused pregnant women to eat by mistake; CBA claimed 406million yuan from](/img/f6/03e39799db36c33a58127359aa2794.png)
[dark horse morning post] many apps under bytek have been taken off the shelves; The leakage of deoxidizer in three squirrels caused pregnant women to eat by mistake; CBA claimed 406million yuan from
随机推荐
基于标签嵌入注意力机制的多任务文本分类模型
404 pages and routing hooks
ROS2学习(1)ROS2简述
A survey of machine learning based technology term recognition
初识Opencv4.X----图像透视变换
Polymorphic case - making drinks
MLX90640 红外热成像仪测温传感器模块开发笔记(六)
IDEA(warning)No artifacts configured
消息的订阅和发布
Plato Farm有望通过Elephant Swap,进一步向外拓展生态
Jenkins 中 shell 脚本执行失败却不自行退出
Circular queue (implemented in C language)
[noip2003 popularity group] stack
Go multithread communication, control coordination and main thread shutdown (sync.waitgroup)
gdb常用命令
POM file details
I. creation and constraint of MySQL table
Docker container MySQL enables binlog and scheduled backup
421. 数组中两个数的最大异或值
OA项目之我的会议