C++中,往往令人头痛的是指针的管理问题!在对象动态构建时,我们需要将对象指针进行存储,一旦忘记释放,那么将会导致不可预估的错误。在C++中排查指针导致的内存泄漏问题实在令人头痛!在虚幻中,为了解决此类问题,加入了智能指针(共享指针,共享引用,弱指针),当我们使用动态方式构建对象时,再也不需要担心内存释放问题!指针的释放规则由引擎制定,包括释放时机!
1、自定义类
在构建自定义类时,我们经常遇到一种情况,当类中持有U类对象指针时,我们希望阻止垃圾回收器对对象释放。但是自定义类中又无法使用UPROPERTY宏,那么我们可以采取将类继承自FGCObject,并重写父类函数AddReferencedObjects。将需要阻止释放的指针加入到操作队列,以防止对象被垃圾回收器回收!
注意:当构建类被释放时(需要我们保证),并且调用其析构函数(析构函数需要重写父类析构函数),对象将自动清除其所添加的所有引用。
2、智能指针
- 虚幻中存在一套非常强大的动态内存管理机制,而这套机制中根本在于智能指针(非侵入式),并且UE的智能指针速度相比STL更快,速度和普通C++指针速度一样。
- 智能指针本质的目的是将释放内存工作进行托管。当两个智能指针指向同一个空间,一个设置为空,另一个不会跟随为空,智能指针设置为空并不是释放内存空间,只是在减少空间引用。
注意:智能指针只能使用于自定义类,U类禁止使用
共享指针和共享引用的优点:
三个指针
3、共享指针
共享指针是虚幻中最常用的智能指针,在操作上可以帮助我们构建托管内存指针!共享指针本身非侵入式的,这使得指针的使用与操作和普通指针一致!共享指针支持主动指向空,并且共享指针是线程安全的,节省内存,性能高效
注意:构建自定义类时,需要使用 F 开头
基本操作语法:
// 自定义类 class MX_API FTestClass { public: FTestClass(); ~FTestClass(); void TestFun(); };
// 其他类
// 构建一个共享指针,但是没有维护任何空间 TSharedPtr<FTestClass> Ftc01;// 不推荐 // 构建一个共享指针,并维护一快内存 TSharedPtr<FTestClass> Ftc02(new FTestClass()); //MakeShareable函数是用来构建共享指针的快捷方式 // 构建一个共享指针,并维护一快内存 TSharedPtr<FTestClass> Ftc03 = MakeShareable(new FTestClass()); // 解引用和操作 Ftc02->TestFun(); Ftc02.Get()->TestFun(); (*Ftc02).TestFun(); // 比较两个智能管理的内存是否是同一个 if (Ftc02 == Ftc03) {} // 判断是否为空 注意操作函数是共享指针的成员函数 if (Ftc02.IsValid()) {} // 注意操作函数是共享指针的成员函数 if (Ftc02.Get() == nullptr) {} // 获取引用计时器 获得当前地址被引用个数 Ftc02.GetSharedReferenceCount(); // 释放 Ftc02.Reset(); Ftc03 = nullptr;
4、共享引用
- 共享引用禁止为空,表明了共享引用创建后必须给予有效初始化,可以使得代码更加安全简洁,保证了对象访问的安全性。无法主动释放共享引用,可以跟随对象释放减少引用计数器
- 共享引用的安全性体现在,如果使用共享引用构建的对象,无法将对象空间设置为空。如果想释放内存,可以借助指向其他共享引用来减少引用计数,来释放空间
- 共享引用本质,无法主动减少引用计数器,只能通过被动方法,例如生命周期终结,共享引用易主
基本语法操作
// 定义 TSharedRef<FTestClass> Ftc01;// 错误执行将导致崩溃 TSharedRef<FTestClass> Ftc02(new FTestClass);// 正确 // 解引用操作 Ftc02->TestFun(); (*Ftc02).TestFun(); // 返回cosnt 引用 ,禁止将对象主动释放 const FTestClass& Ftc03 = Ftc02.Get(); // 和共享指针转换 // 共享引用支持隐式转换为共享指针,由于共享引用是安全的,所以转换是隐式转换 TSharedPtr<FTestClass> Ftc04 = Ftc02; // 从共享指针转换到共享引用是不安全的,所以需要调用TS函数 TSharedRef<FTestClass> Ftc05 = Ftc04.ToSharedRef();
5、弱指针
- 不会阻止对象的销毁,如果引用对象被销毁,则弱指针也将自动清空。一般弱指针的操作意图是保存了一个到达目标对象的指针,担不会控制该对象的生命周期,弱指针不会增加引用计数,可以用来断开引用循环问题。 、
- 无论谁销毁了对象,只要其对象被销毁,弱指针都将自动清空,这使你能够安全缓存指向可变对象的指针。这也意味着,弱指针可能会意外清空,并且,你可以使用弱指针断开引用循环。
- 当不再存在对对象的共享引用时,弱指针的对象将被销毁。
- 弱指针有助于表明意图。当你在某个类中看到一个弱指针时,你就会明白该类仅缓存指向对象的指针,它并不控制它的生命周期。
基本语法操作
// 定义 // 构建空的弱指针 TWeakPtr<FTestClass> WpFtc01; // 利用共享指针构建弱指针 TSharedPtr<FTestClass> PFtc; TWeakPtr<FTestClass> WpFtc02(PFtc); // 利用共享引用构建弱指针 TSharedRef<FTestClass> RFtc; TWeakPtr<FTestClass> WpFtc03(RFtc); // 检查是否有效 // 检查弱指针指向的对象空间是否存在 if (WpFtc01.IsValid()) {} // 释放操作 // 主动释放,但是不会影响引用计数 WpFtc01 = nullptr;
总结
- 一块内存,如果存在有效引用(可直接到达内存的操作方式),则我们可以认为当前内存是有效并且合理的!但是当一块内存不存在引用,则我们可以视为此块内存为被弃用无效的,则可以回收重复利用,这就是内存垃圾回收机制的基本原理。
- 智能指针强调的是当前内存的使用者存在多少,当不存在时,进行回收!
- 注意:智能指针构建的均是栈对象数据类型
标签:对象,C++,内存,共享,指针,Ftc02,引用 From: https://www.cnblogs.com/limu-zy/p/16722326.html