[BUG] UObject BeginDestroy Called Incorrectly?

Hi

I have had a problem which was difficult to diagnose where a class I had derived from UObject attached to my GameState object was suddenly becoming invalid. The values stored within it suddenly became garbage.

The class was added as derived from UObejct through Editor > Add Code

The object was constructed in my GameState constructor using NewObject <T>

After overriding the BeginDestroy method on my UObject, this method is being called after an arbitrary amount of time even though my GameState object still has a valid reference to it.

Is this a defect or am I not correctly handling reference counter on my object?

EDIT:

GameMode class is defined thusly:

#pragma once
#include "SandboxGameMode.generated.h"

UCLASS(minimalapi)
class ASandboxGameMode : public AGameMode
{
    GENERATED_UCLASS_BODY()

    /** Specifies game time start date */
    UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category=Time)
    FDateTime GameStartDateTime;
 
    EGameModePlayState::Type GetCurrentPlayState() const;

    // Overrides
    virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override;
    virtual void InitGameState() override;
    virtual void Tick(float deltaSeconds) override;

private:
    /** Manage current play state */
    TEnumAsByte<EGameModePlayState::Type> m_currentPlayState;
};

The GameState is set in the GameMode constructor as:

GameStateClass = ASandboxGameState::StaticClass();

The GameState class is defined thusly

#pragma once
#include "GameFramework/GameState.h"
#include "DateTimeController.h"
#include "SandboxGameState.generated.h"

UCLASS()
class SANDBOX_API ASandboxGameState : public AGameState
{
    GENERATED_UCLASS_BODY()

    /** */
    UFUNCTION(BlueprintCallable, Category = GameState)
    FDateTimeState& GetDateTimeState();

    void UpdateFromTick(float deltaSeconds);
    virtual void BeginDestroy() override;
private:
    /** */
    UDateTimeController* m_dateTimeController;
};

DateTimeController is created as so in GameState constructor:

// Constructe Date and Time Controller for game
m_dateTimeController = NewObject<UDateTimeController>();

The DateTimeContoller is defined as follows

#pragma once
#include "Object.h"
#include "DateTimeController.generated.h"

UENUM(BlueprintType)
namespace EDayCycle
{
    enum Type
    {
        None UMETA(DisplayName = "None"),
        Dawn UMETA(DisplayName = "Dawn"),
        Day UMETA(DisplayName = "Day"),
        Dusk UMETA(DisplayName = "Dusk"),
        Night UMETA(DisplayName = "Night")
    };
}

/**
* Blueprint Integration Data Structure
*/
USTRUCT(BlueprintType)
struct FDateTimeState
{
    GENERATED_USTRUCT_BODY()

    /** Specifies the current cycle of the day */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Time)
    TEnumAsByte<EDayCycle::Type> DayCycle;

    /** Specifies current in game date and time */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Time)
    FDateTime GameDateTime;

    /** Specifies the current position for the sun */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Time)
    FRotator SunDirection;
};

/**
 * 
 */
class SANDBOX_API UDateTimeController : public UObject
{
    GENERATED_UCLASS_BODY()

    /** Struct to maintain DateTime state */
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Time)
    FDateTimeState DateTimeInstance;

    void UpdateFromTick(float deltaSeconds);
    virtual void BeginDestroy() override;

private:
    void UpdateSunPosition();

    // Number of ticks in a day
    static const int64 TICKS_PER_DAY;
    // Number of ticks in a day
    static const int64 TICKS_PER_HOUR;
    // Number of ticks in a day
    static const int32 TICKS_PER_SECOND;
};

Can you please output the class declaration that is holding the reference to the game state and to the declaration of the game state you created that is referencing this other new UObject.

Does everything have a UPROPERTY declaration above it? I’m pretty sure your object is getting garbage collected, which would mean a valid path from root to your object cannot be found.

Depending on who is holding onto what and how this should be straightforward to address.

    UCLASS()
    class A : public UObject
    {
    GENERATED_UCLASS_BODY()

    UPROPERTY()
    AMyGameState* MyGameState;
    }
    
    UCLASS()
    class AMyGameState : public AActor 
    {
    GENERATED_UCLASS_BODY()

    UPROPERTY()
    USomeOtherObject* OtherObject;
    }
    
    UCLASS()
    class USomeOtherObject : public UObject
    {
    GENERATED_UCLASS_BODY()
    }

I have updated the question with class definitions as requested

Yup, you seem to be missing a UPROPERTY right here

private:
    /** */
    UDateTimeController* m_dateTimeController;

should be

private:

    /** */
    UPROPERTY()
    UDateTimeController* m_dateTimeController;

So you have to UPROPERTY all member variables regardless of whether they will be exposed to engine classes or blueprints?

And is it the same rule for UFUNCTION macro for all member functions regardless?

Thanks

UPROPERTY tells our reflection system about the existence of the variable. Not everything has to be a UPROPERTY, but UObjects by their association with garbage collection do.

If you want to serialize out a class to the network or disk only the variables that are marked UPROPERTY will be saved.

There are more advanced ways to have classes/objects tell the garbage collection system about their lifetime and to do custom serialization, but for now if you want automated/free features, this is the way to do it.

Thanks very much