How to initialize a const member using NewObject<>()

I did blueprint UI scripting for a year, till recently I read a book about how code ‘smells bad’. I tried refactoring my ‘code’, and found too many things I cannot solve. I searched stockoverflow, forums, and other website for these questions, but I got few answers. I am a green horn when it comes to Unreal Engine Programming, maybe it is ‘bad thought’ other than ‘bad smell’ that cause the problem in the first place, and I didn’t find out. For example, what is a good singleton implementation? Most rated answer is to avoid using singleton because it is not threadsafe, use static member in stead.
Sorry for this long intro… If there is a better way to make a member not changeable without a const qualifier, that helps a lot more.

Here is my TileID class containing a const position(ID) in its coordinates and a map for its neighbour Tiles, which is expected to be const. Since UECxx has its unique NewObject method, I found no way to “initialize” const member.

/* My Id class in MyID.h */
UCLASS()
class UMyID : public UObject
{
    GENERATED_BODY()
public:
UMyID();
//UMyID(const FVector& InID, TArray<FVector> InNeighbours); //complie error Error C2550 
Init(const FVector InID, const TArray<FVector>& InNeighbours){
  ID = InID; //failed
  for(auto n : InNeighbours) Neighbours.Add(n); //no valid .Add()
}

protected:
    const FVector ID;
    const TArray<FVector> Neighbours;
};

/* Constructing IDs in Build.cpp */
#include "MyID.h"

void GetNeighbourVectors(TArray<FVector>& OutNeighbours, FVector Position){...}

void BuildSomething(const TArray<FVector>& Position, 
                    TArray<UMyID*>& OutTiles){
  for (auto v : Position){
    TArray<FVector> Neighbours;
    GetNeighbourVectors(Neighbours, v);

    auto NewTile = NewObject<UMyID>(this);
    //NewTile->Init(v, Neighbours);

    //auto NewTile = UMyID(v, Neighbours);

    OutTiles.Add(NewTile);
  }
}

I think you need an initialisation list.

UMyID(const FVector& InID, TArray InNeighbours) : ID (InID), Neighbours (InNeighbours){}

I don’t know if having const members is used in game code in Unreal, in fact I don’t think I remember ever seeing it

Why not keep your fields private and only have Getters or const functions?

In regards to your singleton questions, subsystems are a pretty good way to have singletons

I don’t think there’s any way to create custom constructor for UObjects. Unreal Engine doesn’t work that way. UE uses a concept of a class default object (CDO) and the constructors are used for that. When you create a new object, it copies the data from the default object. After that, you can change its values. So I don’t think you can use const members at all.

As @zeaf has said, you can use public getters if you don’t want anything changing it. But if you’re only worried about Blueprints changing properties, you can set the ID and Neighbours with the UPROPERTY macro and use the BlueprintReadOnly tag. I think you can even make them visible to blueprints when they’re in the private method. So in C++, you must use the getters. In BP, use the properties (or the getters).

(TL;DR use structs)

As far as I know, in UE you cannot use constructor arguments for UObjects because, as you have noticed, they are instanciated through NewObject<>();

The way to go about it would be to either have default values for your properties if they are unchanging, or to use some kind of initialization function after the fact. Of course, it makes the properties not const, but we don’t do const properties for UObjects.

By the way, for actors, you can do a SpawnActorDeferred and initialize properties before finishing the spawn, but that’s outside the scope of your question.


The answer:

Judging by the illustration code you provided however, I believe there is a much simpler solution: You may want to consider using structs instead of objects. It seems like your object wants to be a mere data storage class for an single specialized entity that is part of a whole system. And this system will iterate onto those entities to fulfill its purpose.

To me, this screams “structs” :smiley:

I know that in C++, classes and structs are essentially the same thing, but in UE they have wholly different purposes & usage. For instance, you can use regular constructors for your structs. And since you don’t need to use UPROPERTIES, I’m guessing you can even have your properties be const without it messing up anything.

Edit: spelling

Not a bad idea. Structs are not managed by the GC. So if you dynamically allocated them, you have to manually track their lifetime. You can store them in TSharedPtr. Should work with USTRUCT’s as well and that lets you use UPROPERTY if you want.

True that the whole thing is better a struct. This would help initializing const members, but the object holding the struct is still unable to make struct menber const specified…Actually there is a ‘Const’ Metadata specifier for UCLASS() and stuff being used in Lyra Game Example, just as @Zeaf has said, members are not const specified. And these class member are EditDefaultOnly in editor.
I didn’t dig further into this const thing, and I’d better not take UE cpp as normal cpp.
Thanks a lot guys!!

Quick tip about dynamic allocation of structs, you can also wrap them in a UObject wrapper whose only goal is to hold onto the struct. This way your struct is essentially managed by the GC -and never cloned- without you having to actually use any kind of complex pointer.

Is it good? Probably not better than a SharedPtr, but I’ve used it when I was beginner and so I’ve kept using it in projects that have been ongoing since that time. Obviously, if you have a gazillion struct instances, that’s not a good idea. But for big structs that are few in number and queried often, it’s a viable alternative to SharedPtr structs I suppose…

I’m mostly focused on C++ so I don’t know how the BP side reacts to SharedPtr structs, but if there’s any issue, at least you know that there’s the failsafe option of a simple UObject ptr instead.

its a new system so i could be wrong but i think FInstancedStruct is a new alternative to using UObject wrappers.

1 Like

Very interesting, thanks for the info, I missed the arrival of this one :slight_smile: