UPROPERTY уничтожен после создания актера

Не могу понять в чем проблема. Я создал 2 класса AMyActor и UObject. В AMyActor есть поле UObject, помеченное как свойство. По какой-то причине после конструктора AMyActor сборщик мусора удаляет объект UObject.

МойАктер.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "MyObject.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class MYPROJECT2_API AMyActor : public AActor
{
    GENERATED_BODY()

public: 
    // Sets default values for this actor's properties
    AMyActor();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    UPROPERTY()
    UObject *obj;

    UPROPERTY(EditAnywhere)
    UStaticMeshComponent *mesh;
};

MyActor.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyActor.h"


// Sets default values
AMyActor::AMyActor()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;
    obj = NewObject<UMyObject>();
    mesh = CreateDefaultSubobject<UStaticMeshComponent>("ms");
    UE_LOG(LogTemp, Warning, TEXT("actor create %d %d"), this, obj);
}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
    Super::BeginPlay();

}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    UE_LOG(LogTemp, Warning, TEXT("actor %d %d"), this, obj);
}

МойОбъект.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "MyObject.generated.h"

/**
 * 
 */
UCLASS()
class MYPROJECT2_API UMyObject : public UObject
{
    GENERATED_BODY()

    UMyObject()
    {
        UE_LOG(LogTemp, Warning, TEXT("object create %d"), this);
    }

    ~UMyObject()
    {
        UE_LOG(LogTemp, Warning, TEXT("object destroy %d"), this);
    }
};

Выход

PIE: New page: PIE session: Minimal_Default (Feb 17, 2019, 7:48:39 PM)
LogPlayLevel: Creating play world package: /Game/StarterContent/Maps/UEDPIE_0_Minimal_Default
LogTemp: Warning: object create 1801824896
LogTemp: Warning: actor create 1441518592 1801824896
LogPlayLevel: PIE: StaticDuplicateObject took: (0.005484s)
LogAIModule: Creating AISystem for world Minimal_Default
LogPlayLevel: PIE: World Init took: (0.001288s)
LogPlayLevel: PIE: Created PIE world by copying editor world from /Game/StarterContent/Maps/Minimal_Default.Minimal_Default to /Game/StarterContent/Maps/UEDPIE_0_Minimal_Default.Minimal_Default (0.007418s)
LogTemp: Warning: object destroy 1801824896
LogInit: XAudio2 using 'Speakers (Realtek High Definition Audio(SST))' : 2 channels at 48 kHz using 32 bits per sample (channel mask 0x3)
LogInit: FAudioDevice initialized.
LogUObjectGlobals: Warning: Failed to find object 'Class /Script/MyProject2.MyProject2GameMode'
LogLoad: Game class is 'GameModeBase'
LogWorld: Bringing World /Game/StarterContent/Maps/UEDPIE_0_Minimal_Default.Minimal_Default up for play (max tick rate 60) at 2019.02.17-17.48.39
LogWorld: Bringing up level for play took: 0.002244
LogContentBrowser: Native class hierarchy updated for 'MovieSceneCapture' in 0.0004 seconds. Added 10 classes and 0 folders.
PIE: Play in editor start time for /Game/StarterContent/Maps/UEDPIE_0_Minimal_Default 0.179
LogBlueprintUserMessages: Late PlayInEditor Detection: Level '/Game/StarterContent/Maps/Minimal_Default.Minimal_Default:PersistentLevel' has LevelScriptBlueprint '/Game/StarterContent/Maps/Minimal_Default.Minimal_Default:PersistentLevel.Minimal_Default' with GeneratedClass '/Game/StarterContent/Maps/Minimal_Default.Minimal_Default_C' with ClassGeneratedBy '/
Game/StarterContent/Maps/Minimal_Default.Minimal_Default:PersistentLevel.Minimal_Default'
LogTemp: Warning: actor 1441518592 0
LogTemp: Warning: actor 1441518592 0
LogTemp: Warning: actor 1441518592 0
LogTemp: Warning: actor 1441518592 0
LogTemp: Warning: actor 1441518592 0
LogTemp: Warning: actor 1441518592 0
LogTemp: Warning: actor 1441518592 0

person kosiparcel    schedule 17.02.2019    source источник
comment
Будет ли это работать, если вы переместите obj = NewObject<UMyObject>(); в методе BeginPlay()?   -  person Pascal Goldbach    schedule 19.02.2019


Ответы (1)


На самом деле классы UE4 работают не так; это немного головной убор.

Конструктор UCLASS не является функцией, вызываемой для вашего объекта (т. е. экземпляра класса) при его создании (как можно было бы ожидать, используя "ванильные" объекты C++). Вместо этого конструктор класса отвечает за создание объекта класса по умолчанию (CDO). Затем CDO используется в качестве шаблона при создании экземпляра класса. Аналогично, CDO — это экземпляр класса «мастер-диск», используемый для создания других объектов. Ваш конструктор UCLASS вызывается только один раз: в CDO.

Итак, вызвав NewObject, вы создали новый объект и присвоили указатель на этот объект члену obj CDO. Затем вы продолжаете создавать экземпляр актера в мире, и ваш указатель равен нулю. Ваш объект не был удален сборщиком мусора; он никогда не был назначен в первую очередь.

Вместо NewObject вам нужно позвонить CreateDefaultSubobject. Это сообщает CDO, что новый объект указанного в шаблоне типа должен быть создан при создании экземпляра вашего актора AMyActor. NewObject предназначен для динамически порождаемых объектов, вызываемых между PreInitializeComponents и EndPlay в жизненном цикле актора.

TL;DR: измените свой вызов NewObject на CreateDefaultSubobject, если вы хотите вызвать его в конструкторе. В качестве альтернативы переместите вызов NewObject в функцию PostInitializeComponents вашего актера.

https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/Objects https://docs.unrealengine.com/en-us/Programming/UnrealArchitecture/Actors/ActorLifecycle

NB. Имейте в виду, что предоставленная ссылка на документацию по объектам ужасно устарела (v4.11; я заметил, что она ссылается на ConstructObject, которая с тех пор устарела и удалена). Однако то, что говорится о CDO, не изменилось на момент написания (4.21).

person Rab    schedule 19.02.2019