tsharedptr仅适用于非uobject类型,如fstring、自定义结构体或第三方sdk数据,用于跨线程共享且需引用计数管理;绝不可用于aactor等uobject子类,否则绕过gc导致悬空崩溃。

什么时候该用 TSharedPtr,而不是 TObjectPtr 或裸指针
UE5.4+ 推荐用 TObjectPtr 管理 UObject 子类,TSharedPtr 仅适用于非 UObject 类型(比如纯 C++ 数据结构、工具类、网络消息体)。硬用 TSharedPtr 持有 AActor 或 UActorComponent 会导致对象销毁后悬空,且无法被 GC 追踪——因为 TSharedPtr 不参与 UE 的引用计数机制。
常见错误现象:TSharedPtr<acharacter> PlayerRef;</acharacter> 编译能过,但角色被 Destroy 后指针仍非空,解引用直接 crash。
- 只对继承自
UObject的类型用TObjectPtr或TWeakObjectPtr -
TSharedPtr适合封装FString、自定义FMyDataStruct、第三方 SDK 回调上下文等无生命周期托管需求的对象 - 若需跨线程共享非 UObject 数据,
TSharedPtr是合理选择(它线程安全的引用计数)
TWeakObjectPtr 怎么避免访问已销毁的 UObject
TWeakObjectPtr 是 UE 对 UObject 的弱引用封装,不增加 GC 引用计数,访问前必须调用 IsValid() 或 Get() 判空。它不是“自动变 nullptr”,而是每次访问都查 Object 的内部标记位(IsPendingKill() + 是否已被 GC 清理)。
典型误用:if (WeakRef) { WeakRef->DoSomething(); } —— 这里隐式调用了 operator bool(),它只检查是否为空指针,**不检查 UObject 是否有效**,可能 crash。
- 必须显式写
if (WeakRef.IsValid()) { WeakRef->DoSomething(); } - 在 Tick 或事件回调中频繁访问时,建议先
auto Obj = WeakRef.Get(); if (Obj) { ... },避免多次查表开销 - 不能用
TWeakObjectPtr延长 UObject 生命周期;它只是“观察者”,不是所有者
TSharedPtr 和 TWeakPtr 配合使用的正确姿势
当你要共享一个非 UObject 的资源(比如一个运行时生成的纹理缓存类 FCustomTextureCache),又需要避免循环引用导致内存泄漏,就得配对使用 TSharedPtr 和 TWeakPtr。
通过 REST API 管理 Kibana 保存的对象(仪表板、Lens 可视化等)。适用于:① 以编程方式创建、更新、删除仪表板和 Lens 可视化。
错误示范:两个 TSharedPtr 互相持有对方,引用计数永远不归零,对象永不析构。
- 所有权方用
TSharedPtr(例如管理器类里存TSharedPtr<fcustomtexturecache></fcustomtexturecache>) - 被依赖方用
TWeakPtr(例如缓存项内部回调里存TWeakPtr<ftexturemanager></ftexturemanager>) - 调用
TWeakPtr::Pin()可临时转成TSharedPtr,确保访问期间对象存活;但别滥用,Pin 失败会返回空TSharedPtr -
TWeakPtr本身不参与构造/析构,开销极低,适合大量存储
UE 中混用智能指针的兼容性陷阱
UE 的智能指针不是标准库的 std::shared_ptr,它们不兼容。你不能把 TSharedPtr<int32></int32> 直接传给期望 std::shared_ptr<int32></int32> 的第三方库函数,反之亦然。
更隐蔽的问题是:UE 的 TSharedPtr 默认不支持自定义删除器(如 std::shared_ptr 的 Deleter 参数),也不能用 make_shared 构造——必须用 MakeShared()(注意大小写)。
- 跨模块传递时,如果对方是纯 C++ 库,优先用裸指针 + 明确生命周期约定,或封装一层适配器
-
TSharedPtr::Reset()会立即释放所有权,但不会触发 delete(除非引用计数归零),这点和std::shared_ptr::reset()行为一致 - 在蓝图可调用函数(
UFUNCTION)参数中,禁止使用任何 UE 智能指针类型——蓝图系统不识别它们,只能传 UObject* 或基本类型
最容易被忽略的是:TWeakObjectPtr 在多线程下 IsValid() 是线程安全的,但 Get() 返回的 UObject* 之后的所有操作,都需你自己保证线程安全——UE 不替你加锁。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










