美文网首页
21 UE5 指针:智能指针 和 STL指针

21 UE5 指针:智能指针 和 STL指针

作者: 游戏开发程序员 | 来源:发表于2024-04-06 23:19 被阅读0次

STL 智能指针

  • auto_ptr、unique_ptr、shared_ptr 和 weak_ptr。
  • auto_ptr 在 C++11已被摒弃,在C++17中已经移除不可用

unique_ptr

  • 不共享其指针,它不能复制,只能移动.
  • unique_ptr<Obj> p1 = make_unique<Obj>();
  • std::move(p1) 转移
  • p1.get();获取原始指针
  • release : 返回原指针,是否拥有权
  • reset: 换新删旧
  • swap: 交换管理对象

shared_ptr

  • 为多个所有者管理对象在内存中的生命周期而设计
  • 可复制,可移动,通过引用计数技术
  • shared_ptr<Obj> sp(nullptr); 如果需要后面赋值的话
  • sp = make_shared<Obj>(); 构造
  • dynamic_pointer_cast、static_pointer_cast和const_pointer_cast来转换shared_ptr。
  • 类似于dynamic_cast、static_cast和const_cast运算符。

shared_ptr 相关

  • 1 解决环式指向问题:weak_ptr
  • 2 获取自身对象的智能指针:shared_from_this()
  • 3 多组智能指针管理问题: 不可用1个raw pointer构造多个shared_ptr

weak_ptr

  • 无拥有权,可复制,可移动

  • 常用于指向某一shared_ptr指针拥有的内存地址

  • 不会导致引用计数增加或减少。

  • Expired()判断非空后,使用Lock()来获取shared_ptr

  • STL智能指针代码演示

        // shared_ptr:记录数量是一种智能指针, 它能够记录多少个 shared_ptr 共同指向一个对象, 
        // 从而消除显示的调用 delete , 当引用计数变为零的时候就会将对象自动删除
        auto shared_pointer = make_shared<int>(10);

        // 获取原始的指针
        auto original_pointer = shared_pointer.get();

        // 查看对象的引用计数
        auto shared_pointer2 = shared_pointer;
        auto count = shared_pointer.use_count();

        // 释放 减少一个数量
        shared_pointer2.reset();

        // 全释放后 再查看原始指针数据已重置
        shared_pointer.reset();

        // unique_ptr 独占的智能指针, 它禁止其他智能指针与其共享同一个对象,从而保证代码的安全
        auto unique_pointer = make_unique<int>(20);

        // 非法获取 auto unique_pointer2 = unique_pointer;

        // 可使用move转移 转移后旧指针失效
        auto unique_pointer2 = move(unique_pointer);

        // 释放控制权,不释放内存
        auto p = unique_pointer2.release();
        *p = 21;

        // 释放内存
        unique_pointer2.reset();

        // weak_ptr 配合shared_ptr而引入,解决shared_ptr的相互引用
        // 不拥有资源的所有权,不能直接使用。无 * 和 ->
        // 通过lock获取,和expired检测是否过期。
        auto shared_p = make_shared<string>("This is shared_ptr!");

        // 不增加计数
        weak_ptr<string> weak_p = shared_p;

        // 没有过期,输出内容
        if (!weak_p.expired())
        {
            // lock()获取智能指针
            auto str = *weak_p.lock();
            *weak_p.lock() = "Change by weak_p";
            str = *weak_p.lock();
        }

        // 清空
        weak_p.reset();

UE指针关系

  • TSharedPtr<---->std::shared_ptr
  • TSharedFromThis<---->std::enable_shared_from_this
  • TWeakPtr<---->std::weak_pt
  • TUniquePtr<---->std::unique_ptr

TSharedPtr

  • 用于UE中非UObject相关的类
  • 非侵入式,性能佳,
  • 优先选择共享引用(不可为空)。

TSharedRef

  • 构造:TSharedPtr<int> sp = MakeShared<int>(666);
  • 构建必须初始化 不可为空
  • 没有空值需求下,优先使用ref而不是ptr
  • 无Reset() 和 IsValid() 接口
  • 共享 +1: TSharedRef<int> sr = sp.ToSharedRef();

TWeakPtr

  • 大多数用于获取SharedPtr
  • 只引用 不计数
  • 通过Pin()获取指向的SharedPtr
  • 源SharedPtr失效,他也失效
        // TSharedPtr
        TSharedPtr<int32> MyIntSharedPtr(new int32(123));
        check(MyIntSharedPtr.IsValid()); // 有效
        check(MyIntSharedPtr.IsUnique()); // 唯一

        TSharedPtr<int32> MyIntSharedPtr2; // 可创建为空
        MyIntSharedPtr2 = MyIntSharedPtr; // 复制
        check(MyIntSharedPtr.GetSharedReferenceCount() == 2);

        const int32 DeferenceTest = *MyIntSharedPtr;
        MyIntSharedPtr.Reset(); // 重置
        check(MyIntSharedPtr.GetSharedReferenceCount() == 0);

        // checkf 调试模式下有效: 断言失败会中断程序,打印日志
        // checkf(MyIntSharedPtr.IsValid(), TEXT("MyIntSharedPtr is not Valid "));
        
        // TWeakPtr
        TSharedPtr<int32> SharedInt(new int32(64));
        TWeakPtr< int32 > WeakInt(SharedInt);
        // Pin() 返回 TSharedPtr
        check(WeakInt.Pin().IsValid());
        WeakInt.Reset(); // 重置后,就失效了
        check(!WeakInt.Pin().IsValid());

        // 绑定的智能指针重置了,也会失效
        TWeakPtr< int32 > WeakInt2(SharedInt);
        SharedInt.Reset();
        check(!WeakInt2.Pin().IsValid());

        // TSharedRef
        // 构造必须初始化 优先使用TSharedRef而不是TSharedPtr
        TSharedRef< float > FloatRef(new float(123.0f));
        const float& MyFloat = *FloatRef; // 获取内容的引用1
        const float& MyFloat2 = FloatRef.Get(); // 获取内容的引用2

        TSharedRef< float > FloatRef2 = FloatRef; // 赋值  保留了123

        FloatRef = MakeShareable(new float(456.0f));

        // 解决类内部获取自身:继承TSharedFromThis, 调用AsShared()
        // 并且声明函数标签 nodiscard : 函数的返回值应该被检查并使用.

TUniquePtr

  • 对内存所有权的唯一性
  • 不能有赋值 和 拷贝操作
  • 只有MoveTemp() 转移内存所有权(类似:std::move())
  • 可用MakeUnique构造
        // TUniquePtr 带参构造函数被关键字 explicit 标记 
        TUniquePtr<int> up1(new int(1));
        // 强烈建议用MakeUnique接口 
        TUniquePtr<int> up2(MakeUnique<int>(2));
        TUniquePtr<int> up3 = MakeUnique<int>(3);

        // 拷贝/赋值重载被关键字 =delete 标记 
        // TUniquePtr<int> up4 = up1; // 编译报错 
        // TUniquePtr<int> up5(up2); // 编译报错 

        // 只能通过 MoveTemp() 转移内存所有权, 
        // 转移后up1 被析构 
        TUniquePtr<int> up6 = MoveTemp(up1);

TSharedFromeThis

  • 类公有继承自TSharedFromTthis<ClassName>
  • 提供两类接口 AsShared() 和 SharedThis()
  • 调用AsShared() 的对象必须是一个智能指针
  • 不能在构造函数内部使用
  • 解决类内部获取指针的问题(会导致被析构多次)
        class MyClass : public TSharedFromThis<MyClass>
        {
        public:
            TSharedRef<MyClass> SharedMyself()
            {
                return SharedThis(this);
            }

            ~MyClass() 
            {
                UE_LOG(TestLog, Warning, TEXT("MyClass deleted"));
            }
        };

        // 普通指针或对象,使用TSharedFromThis内的方法会触发断言 
        TSharedPtr<MyClass> ptr = MakeShared<MyClass>();

        // 通过接口获取类实例的智能引用,维护的是同一块内存,同一个计数器 
        TSharedRef<MyClass> pRef1 = ptr->AsShared();
        TSharedRef<MyClass> pRef2 = ptr->SharedMyself();
  • 以上代码会正确的析构, 以为是一组智能指针.
  • 用直接返回this, 就会导致多组智能指针 ptr(new MyClass)

MakeShared

  • 比直接用普通指针创建效率更高
  • 包括用于TUniquePtr的MakeUnique
  • MakedShared只需要进行一次内存申请(2块内存 1数据1控制块)

MakeShareable

  • 将一个普通指针转换为智能指针
  • MakeShareable 支持自定义删除对象的行为:deleter

为什么不能用普通指针初始化智能指针

  • 普通指针不具备自动管理内存的功能,需要手动调用delete来释放内存。
  • 如果将普通指针直接赋值给智能指针,会导致同一个内存块被智能指针和普通指针同时管理,从而可能导致悬空指针、内存重复释放等严重问题。

TObjectPtr介绍

  • 用于管理对 UObject(Unreal Object)对象的指针。
  • 提供了一些方便的功能,例如自动释放、空指针检查和安全的操作。
  • 自动释放:当 TObjectPtr 对象超出作用域或被销毁时,会调用 Reset() 释放 UObject 对象。
  • 安全性检查: TObjectPtr 提供了成员函数 IsValid() 和 IsValidPtr()
  • 操作符重载: TObjectPtr 重载了箭头操作符 -> 和解引用操作符 *
  • 使用场景: 需要对 UObject 进行动态管理和安全访问的场景中特别有用
  • 内部是一个FObject Handle(本质就是一个指针)

相关文章

  • 再说智能指针

    一 STL的智能指针及使用 STL中智能指针有std::shared_ptr std::weak_ptr std:...

  • C++ STL 之智能指针

    本节我们将介绍 C++ STL 中智能指针的使用。 智能指针(英语:Smart pointer)是一种抽象的数据类...

  • 目录

    智能指针(1) 智能指针(2) 智能指针(3) 智能指针之使用 容器 - vector(1) 容器 - vecto...

  • Android基础--智能指针

    智能指针分为3类为轻量级指针(Light Pointer)、强指针(Strong Pointer)和弱指针(Wea...

  • Android智能指针

    网上已经有很多分析智能指针的文章了,讲得不错的是:Android系统的智能指针(轻量级指针、强指针和弱指针)的实现...

  • C++面试重点再梳理

    智能指针 请讲一下智能指针原理,并实现一个简单的智能指针 智能指针其实不是一个指针。它是一个用来帮助我们管理指针的...

  • rust中的智能指针Box

    rust中的指针大致可以分成三种:引用、裸指针和智能指针。 智能指针实际上是一种结构体,只不过它的行为类似指针。智...

  • 条款 03:尽可能使用const

    const 可以用来修饰指针所指物、指针、引用、函数入参、返回值、STL迭代器等。 一、指针 char st[] ...

  • 智能指针到Android引用计数

    智能指针 LightRefBase RefBaseStrongPointerWeakPointer 智能指针 这是...

  • chrome中智能指针使用

    chrom中智能指针的概述和作用 chrome中智能指针的用法和总结 包含如下四种智能指针:scoped_ptr ...

网友评论

      本文标题:21 UE5 指针:智能指针 和 STL指针

      本文链接:https://www.haomeiwen.com/subject/kughzdtx.html