UE4中如何正确使用多个析构函数

How to properly use multiple destructors in UE4

在我的游戏中,我正在创建一些大 class,它存储对较小 classes 的引用,它们也存储一些引用。在游戏过程中,我需要通过销毁它并创建一个新的来重新创建这个大 class 及其所有依赖项。

它的创作看起来像这样:

ABigClass::ABigClass()
{
    UE_LOG(LogTemp, Warning, TEXT("BigClass created"));
    SmallClass1 = NewObject<ASmallClass>();
    SmallClass2 = NewObject<ASmallClass>();
    ......
}

并且有效。现在我想通过从某个函数调用来销毁并重新创建它

BigClass->~ABigClass();
BigClass= NewObject<ABigClass>();

破坏了 BigClass 并用新的小 classes 创建了一个新的,问题是,旧的小 classes 仍然在内存中,我可以通过记录他们的析构函数。

所以我尝试为 Big Class

制作这样的析构函数
ABigClass::~ABigClass()
{
    SmallClass1->~ASmallClass();
    SmallClass2->~ASmallClass();
    ......
    UE_LOG(LogTemp, Warning, TEXT("BigClass destroyed"));
}

小Class继承自其他class,有自己的构造函数和析构函数,但我没有在任何地方调用它。

有时可以,但大多数情况下会导致 UE 编辑器在代码编译或游戏时崩溃 starsted/stopped。

可能有一些更常见的方法来做我想做的事情?或者一些可以防止它崩溃的验证?

请帮忙。

不要手动调用析构函数。替换

SmallClass1->~ASmallClass();
SmallClass2->~ASmallClass();

delete SmallClass1;
SmallClass1 = nullptr;

或者如果这些类型被 unreal 以某种方式(可能)引用计数,则什么也没有。

终于找到方法了。 首先,我需要摆脱所有与 classes 相关的 UPROPERTY,我将要销毁它们,class 中的 UPROPERTY 除外,它控制它们的创建和销毁。如果我需要将这些 classes 暴露给其他地方的蓝图,可以使用 BlueprintCallable getter 和 setter 函数来完成。

然后我需要让 UE 的垃圾收集器平静下来,它会在热重载和游戏关闭时以随机顺序销毁对象,忽略我的析构函数层次结构,这会导致试图销毁已经销毁的对象并崩溃。所以在对其他对象进行析构函数之前,我需要检查是否有要销毁的东西,添加 IsValidLowLevel() 检查。

最好使用 DestructItem() 函数而不是 delete 关键字,它似乎在很多方面对垃圾收集器更友好。

另外,我没有找到安全销毁关卡中生成的对象的方法。可能是因为它们在其他地方被引用,但我不知道在哪里,但由于它们在我的层次结构中处于最低级别,我可以在世界上销毁()它们,而不必理会它们何时会被垃圾收集器的意志从内存中消失.

无论如何,我得到了以下代码:

void AGameModeBase::ResetGame()
{
    if (BigClass->IsValidLowLevel()) {
        DestructItem(BigClass);
        BigClass= nullptr;
        BigClass= NewObject<ABigClass>();   
        UE_LOG(LogTemp, Warning, TEXT("Bigclass recreated"));
    }
}

ABigClass::~ABigClass()
{
    if (SmallClass1) {
        if (SmallClass->IsValidLowLevel())
        {
            DestructItem(SmallClass1);  
        }
        SmallClass1 = nullptr;
    }   
    if (SmallClass2) {
        if (SmallClass->IsValidLowLevel())
        {
            DestructItem(SmallClass2);  
        }
        SmallClass2 = nullptr;
    }   
    ...
    UE_LOG(LogTemp, Warning, TEXT("BigClass destroyed"));
}

ASmallClass::~ASmallClass()
{
    for (ATinyClass* q : TinyClasses)
    {
        if (q->IsValidLowLevel())
        {
            q->Destroy();
        }
    }
    TinyClasses = {};

    UE_LOG(LogTemp, Warning, TEXT("SmallClass destroyed"));
}

而且没有崩溃。可能有人会发现它在需要从对象层次结构中清除游戏杆而不完全重新加载它的情况下很有用。