949 字
5 分钟
UE5 智能指针完全指南
深入解析Unreal Engine 5的智能指针系统,涵盖TSharedPtr、TWeakPtr、TSharedRef的用法,以及在游戏开发中的实战技巧
2026-02-26
前言
智能指针是现代C++开发的重要工具,UE5提供了自己的智能指针实现——TSmartPointer系列(TSharedPtr、TWeakPtr、TSharedRef)。
本文系统讲解UE5智能指针的用法,帮你写出更安全的内存管理代码。
为什么使用智能指针?
| 传统指针 | 智能指针 |
|---|---|
| 手动new/delete | 自动内存管理 |
| 容易内存泄漏 | RAII原则 |
| 悬空指针难排查 | 引用计数安全 |
| 所有权不明确 | 所有权清晰 |
基础类型
TSharedPtr 共享指针
#include "CoreMinimal.h"
// 创建共享指针TSharedPtr<FVector> Position = MakeShared<FVector>();
// 使用默认构造TSharedPtr<FVector> Direction = nullptr;
// 从原始指针创建FVector* RawPtr = new FVector(1, 0, 0);TSharedPtr<FVector> Speed = TSharedPtr<FVector>(RawPtr);
// 访问内容float X = Position->X;float Y = (*Direction).Y;TSharedRef 共享引用
// 不可为空的共享指针TSharedRef<FVector> Ref = MakeShared<FVector>();Ref->X = 100.f;
// TSharedRef 可以安全转换为 TSharedPtrTSharedPtr<FVector> Ptr = Ref;TWeakPtr 弱指针
// 不增加引用计数的观察者TWeakPtr<FVector> WeakPosition;
// 从SharedPtr创建TSharedPtr<FVector> Shared = MakeShared<FVector>();TWeakPtr<FVector> Weak = Shared;
// 检查有效性if (Weak.IsValid()){ // 安全使用 TSharedPtr<FVector> Locked = Weak.Pin(); if (Locked) { UE_LOG(LogTemp, Warning, TEXT("X: %f"), Locked->X); }}引用计数
引用计数原理
TSharedPtr<FVector> Ptr1 = MakeShared<FVector>();// 引用计数 = 1
TSharedPtr<FVector> Ptr2 = Ptr1;// 引用计数 = 2
{ TSharedPtr<FVector> Ptr3 = Ptr1; // 引用计数 = 3}// Ptr3 销毁,引用计数 = 2
Ptr1.Reset();// 引用计数 = 1
Ptr2.Reset();// 引用计数 = 0,对象自动销毁手动引用计数
// 共享引用计数对象TSharedRef<int32> CountRef = MakeShared<int32>();*CountRef = 0;
TWeakPtr<int32> Weak = CountRef;
// 在需要的地方增加引用{ TSharedPtr<int32> Temp = CountRef; (*CountRef)++;} // Temp 销毁但不影响原引用线程安全
线程安全版本
// TSharedPtr 默认非线程安全TSharedPtr<FVector> ThreadUnsafe;
// 线程安全版本TSharedPtr<FVector, ESPMode::ThreadSafe> ThreadSafe;
// 在多线程环境中使用void WorkerThread(){ TSharedPtr<FVector, ESPMode::ThreadSafe> LocalCopy = GlobalPtr; if (LocalCopy) { // 安全访问 }}实战用法
缓存管理
class UCachedDataManager : public UObject{public: // 缓存计算结果 TSharedPtr<FVector> GetCachedDirection(FName Key) { if (Cache.Contains(Key)) { return Cache[Key]; }
TSharedPtr<FVector> NewData = ComputeDirection(Key); Cache.Add(Key, NewData); return NewData; }
private: TMap<FName, TSharedPtr<FVector>> Cache;};观察者模式
class FObserverManager{public: void Register(TWeakPtr<FSubject> Observer) { Observers.Add(Observer); }
void Notify() { // 只通知有效且存在的观察者 for (auto It = Observers.CreateIterator(); It; ++It) { if (It->IsValid()) { if (TSharedPtr<FSubject> Observer = It->Pin()) { Observer->OnNotify(); } } else { It.RemoveCurrent(); } } }
private: TArray<TWeakPtr<FSubject>> Observers;};异步加载
TSharedPtr<FAsyncLoadTask> LoadAssetAsync(const FSoftObjectPath& Path){ return TSharedPtr<FAsyncLoadTask>(new FAsyncLoadTask(Path));}
void OnAssetLoaded(TSharedPtr<FAssetData> Asset){ if (Asset.IsValid()) { // 使用加载的资产 ProcessAsset(Asset); }}与UObject的关系
重要限制
// ⚠️ 智能指针不能指向UObject(因为UObject有自己的垃圾回收)// 错误用法TSharedPtr<AActor> Actor = MakeShared<AActor>(); // 编译错误!
// ✅ 正确做法:使用UObject的垃圾回收TWeakObjectPtr<AActor> ActorPtr;
// 或使用TScriptInterfaceTScriptInterface<IActorInterface> ActorInterface;TWeakObjectPtr
// 用于引用UObject而不影响GCTWeakObjectPtr<AActor> CachedActor;
// 存储CachedActor = MyActor;
// 检查有效性if (CachedActor.IsValid()){ AActor* Actor = CachedActor.Get(); // 安全使用}
// 或使用Pinif (TSharedPtr<AActor> Pinned = CachedActor.Pin()){ // 使用Pinned}常见问题
Q: 和标准库智能指针的区别?
A: UE5的TSmartPointer不依赖标准库,更轻量,且与UE的内存管理系统集成。
Q: 什么时候用TWeakPtr?
A: 观察者、缓存、避免循环引用时。
Q: 可以用在蓝图吗?
A: 智能指针是纯C++特性,蓝图无法直接使用。蓝图中用Object指针和接口。
Q: 性能如何?
A: 略有开销(引用计数),但比手动管理安全。游戏关键路径注意测试。
总结
UE5智能指针核心要点:
- TSharedPtr — 共享所有权,自动释放
- TSharedRef — 不可为空的共享指针
- TWeakPtr — 观察者,不增加引用计数
- TWeakObjectPtr — UObject专用弱引用
- ESPMode::ThreadSafe — 多线程版本
智能指针是编写安全、优雅C++代码的利器。
参考资源
🎉 恭喜! 现在你掌握了UE5智能指针的用法!
写作概览
20 篇
文章
2.9万
总字数
2.5h
阅读时长
1,464
均字数
年度发文
2026 20
Unreal相关
Unity相关
写作概览
20 篇
文章
2.9万
总字数
2.5h
阅读时长
1,464
均字数
年度发文
2026 20
Unreal相关
Unity相关