# 智能指针

UObject 本身就可以帮我们做回收,做释放的,为了可以在更好释放内存,避免出现野指针,而出现智能指针

# 为什么使用虚幻 4 的智能指针库?

  1. std::shared_ptr 不是在所有的平台都能用的
  2. 可以和其它虚幻容器及类型无缝协作
  3. 更好的控制平台特性,包括线程处理和优化

# 优点

  1. 可以像常规的 C++ 指针那样复制,解引用,比较共享指针等
  2. 防止内存泄漏:当没有共享引用时资源自动删除
  3. 包含了可以通过多线程安全地进行访问的 “线程安全” 版本
  4. 可以创建任何类型的对象的共享指针
  5. 支持针 “const”、前置声明的不完全类型、类型转换等

# 如何使用智能指针

智能指针的主要类型分为:TSharedPtr, TSharedRef, TWeakPtr, TUniquePtr。

TSharedPtr(共享指针)用法

""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class TestA
{
public:
int32 a;
float b;
};

void TestSharedPtr()
{
//声明
TSharedPtr<TestA>MyTestA;
//分配内存
MyTestA = MakeShareable(new TestA());
//先判读智能指针是否有效
if (MyTestA.IsValid()||MyTestA.Get())
{
//访问
int32 a = MyTestA->a;
//复制指针
TSharedPtr<TestA>MyTesta = MyTestA;
//获取共享指针引用计数
int32 Count = MyTestA.GetSharedReferenceCount();
//销毁对象
MyTesta.Reset();
}
//MyTestA.IsValid()中"."是访问共享指针的成员,而MyTestA->a中"->"是访问这个指针指向的对象中的成员。
};

使用 TSharedRef(共享引用)用法

""
1
2
3
4
5
6
7
8
9
10
voidTestSharedRef()
{
//声明:
TSharedRef<TestA>MyTestB(new TestA());
//访问:
int32 a= MyTestB->a;//方法一
int32 b= (*MyTestB).a;//方法二
//销毁对象
MyTestB.Reset();
};

TSharedPtr 和 TSharedRef 之间的相互转换

""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
voidATestSharedRefAndPtr()
{
//创建普通指针
TestA* MyTestC=new TestA();
//创建共享指针
TSharedPtr<TestA>MyTestA;
//创建共享引用
TSharedRef<TestA>MyTestB(new TestA());

//共享引用转换为共享指针,支持隐式转换
MyTestA= MyTestB;
//普通的指针转换为共享指针
MyTestA= MakeShareable(MyTestC);
//共享指针转换为共享引用,共享指针不能为空
MyTestB= MyTestA.ToSharedRef();
};

使用 TWeakPtr(弱指针)用法

""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
voidTestTWeakPtr()
{
//创建共享指针
TSharedPtr<TestA> _TestA_ptr= MakeShareable(new TestA());
//创建共享引用
TSharedRef<TestA> _TestA_ref(new TestA);
//声明弱指针
TWeakPtr<TestA>Test_e;

//共享指针转换为弱指针
TWeakPtr<TestA>Test_B(_TestA_ptr);
//共享引用转换为弱指针
TWeakPtr<TestA>Test_C(_TestA_ref);

Test_e= Test_B;
Test_e= Test_C;

//使用完弱指针可以重置为nullptr
Test_e=nullptr;

//弱指针转换为共享指针
TSharedPtr<TestA> NewTest(Test_e.Pin());
if (NewTest.IsValid()||NewTest.Get())
{
//访问指针成员
NewTest->a;
}
};

# 共享指针:基类与派生类的转换

""
1
2
3
4
5
6
7
8
classFather{
public:int32 a= 10;
};

classChild:public Father
{
public:int32 b= 20;
};

派生类转换为基类

""
1
2
3
4
5
6
//声明基类共享指针_father
TSharedPtr<Father>_father;
//创建派生类共享指针_Child
TSharedPtr<Child>_child= MakeShareable(new Child);
//派生类转换为基类,支持隐式转换
_father= _child;

基类转换为派生类

""
1
2
3
4
5
6
7
//基类转换为派生类
TSharedPtr<Child>_child= StaticCastSharedPtr<Child>(_father);
//_child调用派生类的成员
if (_child.IsValid())
{
_child->b;
}

常量基类转换为派生类

""
1
2
3
4
5
6
7
8
9
10
11
//创建派生类转为基类的共享指针,支持隐式转换
const TSharedPtr<Father>const_father= MakeShareable(new Child);
//先将基类指针转换为指向基类的指针
TSharedPtr<Father>const_father_a= ConstCastSharedPtr<Father>(_father);
//然后基类转换为派生类
TSharedPtr<Child>_child_a= StaticCastSharedPtr<Child>(_father);
//调用派生类成员
if (_child_a.IsValid())
{
_child_a->b;
}

# 使用 TSharedFromThis

声明一个类 Test 继承自 TSharedFromThis<Test>

""
1
2
3
4
5
classTestAA:public TSharedFromThis<TestAA>{
public:void print()
{
};
};

为什么原生的类要继承自 TSharedFromThis<>

  • TSharedFromThis 是支持线程安全的。
  • TSharedFromThis 里面会保存一个弱引用,可以通过这个弱引用转换为共享指针。

# 用法

""
1
2
3
4
5
6
7
8
9
10
11
//创建共享指针
TSharedPtr<TestAA>test_a= MakeShareable(new TestAA);//在MakeSharedable的时候会生成一个弱引用
//调用成员函数
test_a->print();
//解引用
TestAA* testb= test_a.Get();
//普通的指针转换为共享指针(只有当该类是继承自TSharedFromThis<>同时原本是共享指针的才可以使用AsShared())
if (testb)//先判断指针部位空
{
TSharedPtr<TestAA>testc= testb->AsShared();
}

# 注意事项:

  • 避免将数据作为 TSharedRef 或 TSharedRef 参数传到函数,此操作将因取消引用和引用计数而产生开销。相反,建议将引用对象作为 const & 进行传递。
  • 可将共享指针向前声明为不完整类型。
  • 共享指针与虚幻对象 ( UObject 及其衍生类) 不兼容。引擎具有 UObject 管理的单独内存管理系统,两个系统未互相重叠。
更新于

请我喝[茶]~( ̄▽ ̄)~*

Natsuneko 微信支付

微信支付

Natsuneko 支付宝

支付宝

Natsuneko 贝宝

贝宝