Download

Classes vs structs, mega-confusing

Ok so I’m struggling here. My GameInstance subclass holds all the persistent data for my game, this includes the status of all the characters. so i have a structure



USTRUCT(BlueprintType)
struct FCharacterInfo
{
    UPROPERTY(...)
    int Power;

    UPROPERTY(...)
    int MaxPower;
};


and my GameInstance has



UCLASS(...)
class UMyGameInstance : public UGameInstance
{
    ...
    UFUNCTION(...)
    FCharacterInfo * GetCharacterInfo( FString playerName ) const
    {
        return PlayerinfoMap[name];
    }
}
public:
    TMap<FString,FCharacterInfo *> PlayerInfoMap;
    FCharacterInfo player1Info;
    FCharacterInfo player2Info;
}


In the ctor I add the “&playerXInfo” to the map. But it appears that Unreal doesn’t like pointers to structs. I tried switching to references but that seems to cause crashes - the editor just dies. Do I have to switch to a class to hold character info? I don’t want to subclass ACharacter because those are not persistent so I don’t want to store them in the instance (they are held in the transient GameMode subclass). If I make it into a class, can I just write



auto info = new UCharacterInfo();


or is it more complicated than that?

You don’t need to use pointers for your struct:



    FCharacterInfo GetCharacterInfo( FString playerName ) const
    {
        return PlayerinfoMap[name];
    }

    TMap<FString,FCharacterInfo> PlayerInfoMap;

Yeah, your problem likely is that you do it something like that:

foo::foo(){

FStruct struct = FStruct(foo,bar);
StructMap.Add(&struct);

}

After you leave the constructor, the memory of ‘struct’ will be released, making your pointer point to invalid data. All data that will be pointed to by pointers should be created directly as a pointer, or stored in a way that makes sure they dont get out of scope. Generally, I wouldn’t recommend using pointers with structs at all. Why did you choose to use pointers at the first place?

Ah no the class contained the instances:



class foo
{
    MyStruct instance1;
}

foo::foo()
{
    StructMap.Add( &instance1 );
}


I chose pointers because the data is bound up to widgets in my HUD, and having to make lots of copies of the data fields every time a HUD widget is refreshed seems wasteful.

Don’t worry about that, thats micro-optimization, as long as you don’t copy whole megabytes of data on a regular basis, you don’t really have to worry about that.

Many a little makes a mickle.
I think you’re on the right track trying to utilize references instead of copying data. Make sure to explicitly declare all your values in your default constructor of your USTRUCT.
For example:



USTRUCT()
struct FMyStruct {
         FMyStruct() {
              ClassPointer = nullptr; 
         }
         UPROPERTY()
             AClassPointer* ClassPointer;
}


Otherwise the GC will go nuts.

One good approach is have an TArray<FCharacterInfo> Pool (yes actual objects in the array) and then when we want to use it, use a TSharePtr<FCharacterInfo> to not have to worry about GC!

I was working down a similar line, but ran into issues using raw structs. (I believe 4.12 has struct member by ref functionality added). I took all my struct based data and moved them to a UObject subclass. It is much simpler to tie UMG to classes than to structs.