zoukankan      html  css  js  c++  java
  • UE4智能指针:TUniquePtr

    TUniquePtr(唯一指针,对应c++ 11标准库中unique_ptr:用来取代C++98中的auto_ptr)是“其所指向的对象及其资源”的唯一拥有者,实现了独占式拥有的概念。

    可以绑定单个对象T或对象数组T[],在其内部仅有一个成员变量为T* Ptr,所以其sizeof8

    一旦TUniquePtr对象被销毁【利用c++的RAIIResource Acquisition is Initialization)特性】或变成empty,或者拥有另一个对象,它先前拥有的那个对象及其资源就会被自动销毁。在异常(exception)发生时可帮助避免资源泄漏。

    利用c++对象的RAII特性的典型情况是一个绑定了资源的TUniquePtr局部对象,在离开作用域后,调用其析构函数来自动释放其拥有的资源。

    绑定

    TUniquePtr<int32> up1 = MakeUnique<int32>(236); // *up1为236
    if (up1)  // true
    {
        UE_LOG(LogTemp, Log, TEXT("up1 is valid. value is %d"), *up1); // 日志会打印
    }
    
    TUniquePtr<float> up2 = TUniquePtr<float>(); // up2为nullptr,没绑定
    if (!up2)
    {
        UE_LOG(LogTemp, Log, TEXT("up2 is invalid.")); // 日志会打印
    }
    
    TUniquePtr<float> up2_1; // up2_1为nullptr,没绑定
    if (!up2_1.IsValid())
    {
        UE_LOG(LogTemp, Log, TEXT("up2_1 is invalid.")); // 日志会打印
    }
    
    TUniquePtr<float> up2_2 = nullptr; // up2_2为nullptr,没绑定
    if (up2_2.Get()==nullptr)
    {
        UE_LOG(LogTemp, Log, TEXT("up2_2 is invalid.")); // 日志会打印
    }
    
    TUniquePtr<double> up3(new double(10.8)); // *up3为10.8
    
    up3 = MakeUnique<double>(25.0);  // up3会释放自己原有资源,然后绑定新的资源
    
    //TUniquePtr<int32> up4 = new int32(886); // 编译不过
    
    TUniquePtr<char> CharBuffer1 = MakeUnique<char>(); // *CharBuffer1为''
    *CharBuffer1 = 'X';
    
    TUniquePtr<char[]> CharBuffer2 = MakeUnique<char[]>(25); // CharBuffer2指向25个字节的初始化为0的内存区域
    CharBuffer2[0] = 'T';
    CharBuffer2[1] = 'o';
    
    //TUniquePtr<int32> up5 = up1; // 编译不过
    //TUniquePtr<int32> up6(up1); // 编译不过
    
    TUniquePtr<FVector>&& up7 = MakeUnique<FVector>();
    up7->X = 10;
    up7->Y = 20;
    up7->Z = 30;
    
    TUniquePtr<FString>&& up8 = MakeUnique<FString>(TEXT("china")); // *up8为china
    *up8 = TEXT("shenzhen");  // *up8为shenzhen
    
    TUniquePtr<TArray<FString>> up9 = MakeUnique<TArray<FString>>();
    up9->Add("good"); // 数组中共有1个元素:good
    up9->Add("better"); // 数组中共有2个元素:good  better
    up9->Add("best"); // 数组中共有3个元素:good  better  best
    
    TUniquePtr<int32> up10(new int32(5)); // *up10为5
    up10 = MoveTemp(up1); // up10释放自己原有资源,然后接管up1的资源  *up10为236
    if (up1)  // false
    {
        UE_LOG(LogTemp, Log, TEXT("up1 is valid. value is %d"), *up1);
    }
    
    if (up10.IsValid())  // true
    {
        UE_LOG(LogTemp, Log, TEXT("up10 is valid. value is %d"), *up10); // 日志会打印
    }
    
    int32* ptr1 = new int32(10);
    TUniquePtr<int32> up11(ptr1);
    TUniquePtr<int32> up12 = TUniquePtr<int32>(up11.Release()); // up11不再管理ptr1指针所指向的内存,由up12绑上该地址后进行管理

    一些错误的做法

    ① 将栈内存绑定到TUniquePtr

    int32 n1 = 235;
    TUniquePtr<int32> up1(&n1);

    ② 将同一个对象及其资源绑定在多个TUniquePtr

    int32* p1 = new int32(123);
    TUniquePtr<int32> up1(p1);
    TUniquePtr<int32> up2(p1); // p1不能绑定在多个TUniquePtr对象上,否则会导致被delete多次

    离开作用域,up1、up2生命周期结束后,会delete p1两次。不会立即引起崩溃,而是在后面崩溃在一个奇怪的地方:

    ③ 不能将UObject对象绑定在UniquePtr

    UMyObject* obj1 = NewObject<UMyObject>();
    TUniquePtr<UMyObject> up1 = TUniquePtr<UMyObject>(obj1);// 非法,运行时崩溃!  TUniquePtr不能管理UObject对象

    UObject对象被GC管理,不能绑定在UniquePtr

    UObject对象的析构函数在GC的清扫阶段被调用,此时它的FName必须为NAME_None 

    ④ 用TUniquePtr<T>绑定T数组的内存

    TUniquePtr<FString> up1(new FString[16]);

    离开作用域,up1生命周期结束后,不会立即引起崩溃,而是在后面崩溃在一个奇怪的地方:

    释放

    TUniquePtr<int32> up1(new int32(10));
    up1 = nullptr; // 调用缺省的TDefaultDelete<int32>,释放自己绑定的资源,成员变量Ptr=nullptr
    
    TUniquePtr<double> up2 = MakeUnique<double>();
    up2.Reset(); // 调用缺省的TDefaultDelete<int32>,释放自己绑定的资源,成员变量Ptr=nullptr
    
    TUniquePtr<float> up3 = MakeUnique<float>(3.6f);
    up3.Reset(new float(2.5f)); // 调用缺省的TDefaultDelete<int32>,释放自己原来绑定的资源3.6f,然后重新绑定新的资源2.5f
    
    char* ptr4 = new char('M');
    TUniquePtr<char> up4(ptr4);
    TUniquePtr<char> up5 = TUniquePtr<char>(up4.Release());  // up4不再管理ptr4指针所指向的内存,由up5绑上该地址后进行管理
    
    TUniquePtr<FVector> up6 = MakeUnique<FVector>(1.5f, 1.8f, 2.7f);
    TUniquePtr<FVector> up7 = MoveTemp(up6);  // up6不再管理其绑定的资源,由up7来接管

    数组偏特化版本

    TUniquePtr<int32[]> up1(new int32[5]);
    
    for (int i=0; i<5; i++)
    {
        up1[i] = 100*(i+1);
    }

    Deleter

    单个对象T在释放资源时,其缺省Deleter中会调用delete Ptr

    对象数组T[]在释放资源时,其缺省Deleter中会调用delete[] Ptr

    自定义Deleter

    struct TTest1Delete
    {
        void operator()(int32* Ptr) const
        {
            static int32 s_nSum = 0;
            s_nSum += *Ptr;
    
            UE_LOG(LogTemp, Log, TEXT("s_nSum: %d"), s_nSum);
    
            delete Ptr;
        }
    };
    
    
    TUniquePtr<int32, TTest1Delete> up1(new int32(10));
    TUniquePtr<int32, TTest1Delete> up2(new int32(20));

    执行后,会输出如下log:

    [2020.11.30-07.54.19:916][357]LogTemp: s_nSum: 20
    [2020.11.30-07.54.34:181][357]LogTemp: s_nSum: 30

  • 相关阅读:
    Deepin安装Python开发环境
    Deepin怎样安装C/C++编译环境更好
    当 tcpdump -w 遇到 Permission denied
    c++中的虚函数
    c++中的new 和delete
    ubuntu没有输入窗口,不能调用输入法
    Ubuntu下升级VisualBox后无法启动 Kernel driver not installed (rc=-1908)
    BCD与GRUB
    adb shell device not found解决
    unsupported number of arguments...的错误
  • 原文地址:https://www.cnblogs.com/kekec/p/13933184.html
Copyright © 2011-2022 走看看