在ue4引擎类中几乎有很大一部分的类都继承自UObject,继承UObject的类有很多特性,其中有垃圾回收,网络复制,反射,序列化,自己实现的运行时类型识别。
- 而对于没有继承自UObject的类则不能在引擎关闭时自动进行垃圾回收。在这种情况下如果开发者不手动进行垃圾回收程序的内存很容易爆满,最终崩溃。
- 还有一种情况就是已有一个指针指向一块内存,开发者不小心释放了这块内存区域,但指针忘了赋空。导致形成野指针。
以上的两种情况都是程序员在开发中遇到的问题。有个专业名词概括上述的情况——内存泄漏。
为了避免上述的情况ue4推出了智能指针的概念。
用这篇文章的案例来讲
https://zhuanlan.zhihu.com/p/94198883
- 首先是共享指针
指针类型是TSharedPtr<Aclass>
这个Aclass不能继承自UObject类。
用法:
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中"->"是访问这个指针指向的对象中的成员。
};
- 共享指针可以置为空“Null”
- 在访问共享指针时,要先判读这个共享指针是否有效,如果这个指针无效,将会导致奔溃。
- MyTestA.IsValid()中"."是访问共享指针的成员,而MyTestA->a中"->"是访问这个指针指向的对象中的成员。
//使用
SharedPtr->//(自定义类里的元素) //不推荐这样用 -> 重载运算符 有断言check( IsValid() )
SharedPtr.Get()-> //推荐
解引用和访问
解引用、调用方法及访问成员的操作方式和您处理常规的C++指针的方式一样。
1.MyTestA->ListChildren();
2.MyTestA.Get()->ListChildren();
3. ( *MyTestA ).ListChildren();
通过使用 Reset() 方法或通过赋予NULL值,可以重置共享指针。
1. TestA.Reset();
2. TestA = NULL;
当共享指针离开作用域时,该对象将会销毁。
删除线上的内容有误,因改成当共享指针离开作用域时,该共享指针指向的对象的共享堆上的引用计数减1
删除线上只是针对单个引用计数的情况,如果有多个引用计数的情况会有特殊情况发生比如引用循环
详情参考两位大佬的文章:
https://zhuanlan.zhihu.com/p/179949949
https://www.cnblogs.com/Manual-Linux/p/13181122.html
引用循环同样会造成内存泄漏,解决引用循环的需要用到弱指针。
当引用为0时对象销毁。
- 共享引用
使用TSharedRef(共享引用)用法
void TestSharedRef()
{
//声明:
TSharedRef<TestA>MyTestB(new TestA());
//访问:
int32 a = MyTestB->a;//方法一
int32 b = (*MyTestB).a;//方法二
//销毁对象
MyTestB.Reset();
};
1.与共享指针类似,固定引用非空对象(声明时必须初始化非空)
TSharedPtr 和 TSharedRef之间的相互转换
void ATestSharedRefAndPtr()
{
//创建普通指针
TestA* MyTestC = new TestA();
//创建共享指针
TSharedPtr<TestA>MyTestA;
//创建共享引用
TSharedRef<TestA>MyTestB(new TestA());
//共享引用转换为共享指针,支持隐式转换
MyTestA = MyTestB;
//普通的指针转换为共享指针
MyTestA = MakeShareable(MyTestC);
//共享指针转换为共享引用,共享指针不能为空
MyTestB = MyTestA.ToSharedRef();
//转换
MyTestA.ToSharedRef() //共享指针 转换为 共享引用 不安全 有可能触发断言
MyTestA->AsShared() //继承自TSharedFromThis 将会派生下来获取共享引用的方法
//继承自 TSharedFromThis 的 类 可以通过派生方法直接获取自己的共享引用
MyTestB = MyClass->AsShared();
};
3.弱指针
使用TWeakPtr(弱指针)用法
void TestTWeakPtr()
{
//创建共享指针
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;
}
};
对若指针赋空不会重置弱指针指向的内存区域。
弱指针没办法直接访问对象 必须通过Pin() 来获取共享指针访问对象
其共享指针被清空 弱指针也会被清空
共享指针:基类与派生类的转换
先声明两个类
class Father
{
public:
int32 a = 10;
};
class Child :public Father
{
public:
int32 b = 20;
};
派生类转换为基类
//声明基类共享指针_father
TSharedPtr<Father>_father;
//创建派生类共享指针_Child
TSharedPtr<Child>_child = MakeShareable(new Child);
//派生类转换为基类,支持隐式转换
_father = _child;
基类转换为派生类
//基类转换为派生类
TSharedPtr<Child>_child = StaticCastSharedPtr<Child>(_father);
//_child调用派生类的成员
if (_child.IsValid())
{
_child->b;
}
常量基类转换为派生类
//创建派生类转为基类的共享指针,支持隐式转换
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;
}
共享引用:基类与派生类的转换
用法和共享指针一样,只需修改以下即可
- TsharedPtr改为TSharedRef,
- StaticCastSharedPtr改为StaticCastSharedRef,
- ConstStaticCastSharedPtr改为ConstStaticCastSharedRef
TSharedFromThis
TSharedFromThis是一个模板类,普通C++函数继承TSharedFromThis类后,类将会保存一个弱指针,当通过智能指针获取到该类的普通指针时,可以通过调用AsShared方法获取到该类的智能指针。简而言之,继承该类的普通C++类可以将智能指针获得的普通指针再转为智能指针。
class FTestClass : TSharedFromThis<FTestClass>
{}
TSharedPtr<FTestClass> TestPtr = MakeShareable(new FTestClass());
FTestClass* TestNormalPtr = TestPtr.Get();
TSharedPtr<FTestClass> TestPtr2 = TestNormalPtr->AsShared();
注意:只有通过智能指针获取的普通指针才能使用AsShared转换为智能指针,否则可能崩溃。因为通过MakeShareable创建智能指针时,才会初始化其弱指针。