UE All about pointers
UE All about pointers
使用这些指针类型✔
TSoftObjectPtr
- 用于通过路径引用可能已加载或未加载的对象。
- 即使其他关卡的Actor没有加载,也可以指向它们。
- 当指向资源(如网格)时,可以与异步加载函数一起使用以按需加载它们。
- 与“Soft Object Reference”蓝图变量类型相同。
TSoftClassPtr
- 用于引用可能已加载或未加载的类或蓝图类型。
- 一旦加载,它将为您提供一个可以从中创建实例的类类型。
- 可以与异步加载函数一起使用以加载它们。
- 与“Soft Class Reference”蓝图变量类型相同。
TWeakObjectPtr
- 用于引用已实例化的对象。
- 如果对象被销毁或垃圾回收,将解析为nullptr。
不要使用这些指针类型❌
FSoftObjectPath
- 由其他指针类型☝内部使用。
- 由于它不缓存结果,所以速度较慢。
- 如果在编辑器中设置,它将指向
UBlueprint
类而不是UBlueprintGeneratedClass
,这通常不是游戏玩法代码所需的。 - 编辑器插件的制作者可能需要这个功能。
FSoftClassPath
- 与
FSoftObjectPath
相同,但具有一些与加载类相关的辅助函数。
FSoftObjectPtr
TSoftObjectPtr
的非模板和非BP暴露版本。
Weak vs Soft Pointers
Weak Pointer
- 为指向已 实例化的
UObject
在GUObjectArray
中 创建 或 设置 索引 - 指针无需作为
UPROPERTY
即可知道指向的 对象是否已被垃圾回收
Soft Pointer
- 用 String 代表可能 已加载或未加载 的 对象或资产 的路径。
- 在非编辑器构建中,内部会存储一个额外的 Weak Pointer 来跟踪 查询和查找操作后的 对象。
Soft Pointers
在几乎所有情况下,您应该使用 TSoftObjectPtr
或 TSoftClassPtr
FSoftObjectPath
- 不要为游戏玩法代码创建自己的
FSoftObjectPath
变量。- 它们不缓存已解析的对象,因此每次查询都会重新搜索对象。
- 它们还指向蓝图类资产(
UBlueprint
),而不是生成的类(UBlueprintGeneratedClass
,“_C”在路径名中)。 在打包构建中,
UBlueprint
会被剥离。应使用TSoftObjectPtr
或TSoftClassPtr
。FSoftObjectPath
主要用于软指针的内部使用。SoftObjectPath
变量可以在蓝图中创建,但只能用于编辑器程序- 除非是不想指向
UBlueprintGenerateClass
类,并且不需要缓存。
- 除非是不想指向
- 如果在蓝图中使用,它将只允许选择磁盘上的资产,而不是对象实例。
- 要指向实例,应使用 TSoftObjectPtr。
- 它不是模板化的,要将选择限制为资产类型
- 可以使用 MetaClass UProperty 元数据(或使用 TSoftClassPtr 来代替此类功能)。
当对象被解析时,它将使用哈希来搜索它,与普通指针或弱指针相比,这有一点开销。
- 扩展类通常会缓存它们,因此一旦解析,就不会再次搜索。
FSoftClassPath
- 与
FSoftObjectPath
相同,但具有一些与加载类相关的辅助函数 - 建议使用 TSoftClassPtr
FSoftObjectPtr
- 内部保留一个
FSoftObjectPath
用于查找对象,以及一个FWeakObjectPtr
用于在找到对象后缓存它。 - 不是
USTRUCT
,因此无法在蓝图中使用,仅适用于C++ - 有两个子类型,
TSoftObjectPtr
和TSoftClassPtr
,它们分别提供了一个模板化的、BP可见的方法,用于指向对象实例或资产(CDO)。应该使用它们而不是FSoftObjectPtr
。 - 当调用
Get()
时,它会在基类上调用它,首先检查内部的WeakPtr
是否已经被缓存(在非PIE会话中),否则它将调用FSoftObjectPath.ResolveObject
来查找对象。
TSoftObjectPtr
TSoftObjectPtr
是通用FSoftObjectPtr
的模板化包装器,可以在蓝图中使用。- 可以用于指向具有路径名的任何对象
- 最适合用于指向可能尚未加载的对象,无论是磁盘上的资源还是任何关卡中的对象。
- 当指向的对象尚未加载时调用
Get()
,它将返回nullptr
。一旦加载,它将返回具有匹配全名的Actor,并将其缓存以便进一步查询。
如果您想引用已经实例化的Actor,请改用 TWeakObjectPtr
。
在编辑器中,不能将默认值设置为蓝图类型(请改用 TSoftClassPtr
), 但它可以指向数据资产。
该值可以通过选择已加载的Actor在实例详细信息窗口中设置,也可以在当前打开的地图中为任何Actor设置类默认值。
TSoftClassPtr
TSoftClassPtr
是围绕FSoftObjectPtr
的模板化包装器,类似于TSubclassOf
,可以在UProperties
中用于蓝图子类。- 使用它来指向蓝图类型(
UBlueprintGeneratedClass
),以便查询它们是否已加载。 - 也可以用于异步加载类(或同步加载,尽管这会引入延迟)。
- 但对于
DataAssets
来说不适用,因为它们不应该被实例化,对于这些情况请使用TSoftObjectPtr
。
Weak Pointers
弱指针不像软指针那样存储路径名,它们仅引用已经实例化的对象。
底层原理
弱指针仅存储两个内容:
1 2
int32 ObjectIndex; int32 ObjectSerialNumber;
当调用
Get()
时,它首先会使用ObjectIndex
从GUObjectArray
获取对象(如果存在)。- *但是 `ObjectIndex` 只有32位,如果不断生成和销毁actor,它不是很容易耗尽吗?*
- 理论上是这样,但由于在任何时候最多只有几十万个对象存活,所以这些索引会被重用。
- 正因为如此,我们有
ObjectSerialNumber
来确保在索引重用的情况下,它确实是我们想要的对象。ObjectSerialNumber
仅在第一次将弱指针指向UObject
时分配,否则为零。它是一个线程安全的递增int32
计数器。
- *当我们用完这些序列号时会发生什么?*
- 这就是游戏发生致命断言(即崩溃)的地方。
- 这意味着在用完序列号之前,您最多可以创建 $2147483647$ 个指向唯一
UObject
的新弱指针。 - 对于大多数用例来说,这应该远远超过了足够,但要考虑到非常长时间运行的进程或弱指针的奇怪用法。
- *但是 `ObjectIndex` 只有32位,如果不断生成和销毁actor,它不是很容易耗尽吗?*
在比较序列号之后,它最终检查
UObject
是否有效(IsValid()
)- 如果无效(在
PendingKill
或IsGarbage
的情况下),返回nullptr
, 否则返回对象 - 因此,您可以确保解引用弱指针总是返回有效的
UObject
或nullptr
(如果不存在)。
- 如果无效(在
当使用
AddUObject
/BindUObject
函数时,所有委托都通过弱指针保持对其UObject
的引用,因此您可以安全地订阅委托,而无需担心在销毁期间取消订阅。- 但是
AddRaw
/BindRaw
函数相反,这些函数使用非托管的C++指针,因此要小心处理它们,并尽量不在处理UObject
时使用它们。
- 但是
总而言之,
- 弱指针 是指向
UObject
的一种出色且安全的方法,在取消引用UObject
时会产生一些较小的开销。 - 因为它们处理获取和验证
UObject
的所有内部机制,所以它们也不必是UPROPERTY
。
FWeakObjectPtr
- 不是
USTRUCT
,因此不能在蓝图中使用,只能在 C++ 中使用。 - 一般使用
TWeakObjectPtr
而非FWeakObjectPtr
TWeakObjectPtr
TWeakObjectPtr
是通用FWeakObjectPtr
的模板版本。可以在蓝图中使用,但必须在C++中声明。- 即使它在内部不使用对象的字符串表示,也可以在实例详细信息视图(不是类默认值)中设置该值。
- 因为它不使用字符串路径,所以跳过了查找资产的开销,但它只能设置为已经实例化的对象。
- 在C++中,您可以 指向任何已实例化的
UObject
,无论它所在的关卡,只要它已经加载。
本文由作者按照 CC BY 4.0 进行授权