1
0

虚幻智能指针

2026-10-26

虚幻的智能指针

裸指针四大死法:泄漏、双重释放、悬空指针、异常路径漏 delete。 根源:指针可无限复制,但对象只能死一次——“谁负责销毁”不明确。

对比一下C#

C# 是我们一开始接触的,他是有自动的GC引擎的,因此我们可以对比一下。C#里面的内存管理GC采用,主要流程。

  • 引用树,不可达内存标记,后续GC会进入
  • 内存清理后空余内存处理 (这里处理流派有很多,有留着不动,有压缩,也有直接from复制到to然后from废弃)
  • 现代化采用分代GC,因为大部分的对象都是朝生夕灭的

也就是说在C#里面,我们默认其实用的是共享指针,由Unity进行维护,其实就够了。

虚幻的智能指针

虚幻的GC系统分为两层,一层是基于反射系统的UObject 用于处理所有继承UObject的子类GC
还有一层是基于CPP已有类型的GC 常见的前缀是I,F 也就是 原生class struct 这些。除了上面以外其他对象

以下的是GC系统第二层,用于管理CPP的

TSharedPtr TSharedRef

  • 共享引用,所有权支持复制.
void Test(){
TSharedPtr<FMyShared> Data =MakeShared<FMyShared>();
TSharedPtr<FMyShared> DataB = Data; //支持复制 计数2
}
//移开了函数作用域,自动调用虚构函数,然后计数为零 死亡。
  • TSharedRef 用于传参,一定是非空,函数则不需要频繁if判空
  • 和UObject体系一样的是 TObjectPtr 这个用于UObject子类

TUniquePtr —— 独占(默认首选)

  • 不允许复制所有权,可为空
void Test(){
    TUniquePtr<FData> data = MakeUnique<FData>();
    // TUniquePtr<FData> dataB = data; //报错 不可复制
}

TWeakPtr

  • 弱指针,这个用于解决共享指针相互依赖,永远没办法GC的问题
TWeakPtr<FData> Weak = Strong;                 // 不加计数
if (TSharedPtr<FData> P = Weak.Pin()) {        // 标准用法:Pin+判空(临时续命)
    P->Work();
}

  • 这个是不影响GC的
  • 和UObject体系一样的是 TWeakObjectPtr 这个用于UObject子类

六大场景:① PIMPL 藏实现 ② 工厂返回值 ③ 多态容器/树(命令队列、行为树节点)④ 运行时初始化的子系统 ⑤ 局部 RAII 守卫 ⑥ 拥有型 Map 槽位。 口诀:能确定没有第二个人共享 → 一律 Unique(零开销 + 语义即文档)。

浅拷贝和深拷贝

  • 浅拷贝 A,B都指向同一块内存
  • 深拷贝 A,B 只是数据相同,但是都是独立的。
void Foo(FData  Data);        // ① 按值传   → 完整拷贝一份(拷贝构造)
void Foo(FData& Data);        // ② 引用传   → 不拷贝,直接用本体(可被修改)
void Foo(const FData& Data);  // ③ const 引用 → 不拷贝,只读(最常用)
void Foo(FData* Data);        // ④ 指针传   → 不拷贝对象,拷贝的是地址(8字节)
void Foo(FData&& Data);       // ⑤ 右值引用 → 不拷贝,"接管"临时对象(移动语义)

评论