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 进行授权






