Download

Confused by the following coding style

So, in some of the tutorials I followed I saw something like this on a few occasions:

static ConstructorHelpers::FObjectFinder<UBlueprint> PlayerPawnOb(TEXT(“Blueprint’/Game/Characters/JoyGemBP.JoyGemBP’”));

(this one I picked off of some forum post, but tutorials have something along these lines).

This is usually found in a function and to me it looks like it’s creating a function-static object that it constructs from this location. Why are function statics used ? Why isn’t this a pointer in the class and then something like :

_someClassMember = ConstructorHelpers::FObjectFinder<UBlueprint>(TEXT(“Blueprint’/Game/Characters/JoyGemBP.JoyGemBP’”));

Just don’t like those function statics, is all.

Avoiding Asset References in Code

Hard coded asset references in UE4 C++ are usually avoided, the most notable exception, found even in Epic sample games, is in the Game Mode constructor.

I personally recommend you make a BP of your Game Mode class that you then reference from your project settings / World Settings.

Then you can set your character class and other core classes there instead, thus avoiding the entire issue of hard coded asset paths!

If you have assets you need to refer to in other classes, you can use this syntax in the C++ class, and then set the reference in the blueprinted version of your class in the editor:



/** A Blueprint Class Reference */
UPROPERTY(Category="Your Class References", EditAnywhere, BlueprintReadWrite)
TSubclassOf<AYourBaseCPPClass> YourBP;

/** A Particle Template Reference */
UPROPERTY(Category="Your Class References", EditAnywhere, BlueprintReadWrite)
UParticleSystem* YourParticleTemplate;


The advantage of this is that you avoid having any hard coded asset references at all in C++.

This is important so you can easily rename / move your assets and also ensures proper packaging of the game.

In my own projects I don’t have a single asset path hard coded in C++ any more, it makes reorganizing the project and packaging so nice and simple!

:slight_smile:

Rama

Thanks for your response. One more question - I get the idea of avoiding assests in C++ but just curious why they did it as static function object. Was there a technical reason for it or could it have been a pointer member in the class ? Do they have it simply there because they didn’t feel like adding a member to the class and it was only used in that function so they just winged it?

Again, not saying I’d do this, but just curious from engine memory management, etc, was there a reason to have a static or if they could have used member pointer in the class.

Uuuh… What’s a function-static object?

Anyway, the reason object finders are static is you do not want to rerun the object finding logic every time the constructor is run. Since you’re specifying a hardcoded asset path, that asset path is not going to change during execution and there is no point in repeating the object load.

Don’t disregard fundamental language constructs on a knee-jerk basis, there’s a good reason static storage exists.

And the same applies to things like “avoid asset references in code”. The option exists because sometimes you simply do not need a configurable asset reference and a hardcoded path works just as well. Use your own judgment.

-Camille

I dont believe this is actually a static function, as you are stating, I believe it is actually an abbreviated constructor for a static variable, sort of like this



static FVector Location = FVector(0,0,256);


becomes abbreviated to:



static FVector Location(0,0,256);


So the first call creates a static variable object and does the lookup



static ConstructorHelpers::FClassFinder<APawn> BotPawnOb(TEXT("/Game/Blueprints/Pawns/BotPawn"));


The second call retrieves the internal member, which will never have its lookup process done again since it is a static local variable



BotPawnClass = BotPawnOb.Class;


Actually static variables have an advantage in that they only get set once, for all instances of the class!

So to do a lookup and store it as a static local variable actually can have a performance advantage.

If you look in shootergame’s game mode you also see this sort of a thing:



static ConstructorHelpers::FClassFinder<APawn> BotPawnOb(TEXT("/Game/Blueprints/Pawns/BotPawn"));
BotPawnClass = BotPawnOb.Class;


And elsewhere in game mode you see static variables used like this:



static TArray<APlayerStart*> PreferredSpawns;
static TArray<APlayerStart*> FallbackSpawns;
PreferredSpawns.Reset();
FallbackSpawns.Reset();

for (int32 i = 0; i < PlayerStarts.Num(); i++)
{
	APlayerStart* TestSpawn = PlayerStarts*;
	if (IsSpawnpointAllowed(TestSpawn, Player))
	{


etc


**Summary**

So the use of static local variable is to ensure the lookup is only done once, no matter how many instances of the class need the info :)

More Info on Static Local Variables

More info here!

Have fun today!

:slight_smile:

Rama

Yup - and that 's exactly what I meant when I said “function-static object” (not “static function”). Probably should have said “static variable” to avoid confusion :slight_smile:

So going back to my previous question - "Do they have it simply there because they didn’t feel like adding a member to the class and it was only used in that function so they just winged it? "

My question was - if there was any specific reason they went ahead with static variable or could they have had a pointer in the class , say like private member, and then assign to that in the constructor. The end result would be the same - one time initalization. But I wasn’t quite sure if there is some deeper reason why they had to use it as a static variable , or was it simply because they didn’t feel it was necessary to create a private class memeber. (or they wanted to avoid repeated searches for the object inside the constructor )

So instead of :

static ConstructorHelpers::FObjectFinder<UBlueprint> PlayerPawnOb(TEXT(“Blueprint’/Game/Characters/JoyGemBP.JoyGemBP’”));

which, as you said creates a static variable , then constructs it once , and then it keeps it there without having to reinitialize…

Could they have had:

in . h:

private:
UBlueprint* _myJoyBP.

then in cpp constructor :

_myJoyBP = PlayerPawnOb(TEXT(“Blueprint’/Game/Characters/JoyGemBP.JoyGemBP’”));

and from there they can access it in whichever function they want.

void myobject::a()
{
_myJoyBP->DoThis();
}
void myobject::b()
{
_myJoyBP->DoThat();
}
etc… the behavior is similar to:
void myobject::a()
{
static ConstructorHelpers::FObjectFinder<UBlueprint> myJoyBP(TEXT(“Blueprint’/Game/Characters/JoyGemBP.JoyGemBP’”));
myJoyBP->DoThis();
}
void myobject::b()
{
static ConstructorHelpers::FObjectFinder<UBlueprint> myJoyBP(TEXT(“Blueprint’/Game/Characters/JoyGemBP.JoyGemBP’”));
myJoyBP->DoThat();
}

But I prefer the former style because I don’t have to propagate this initialization around and also if I need to change the object type I need to do it only once.

So my question was if the way they did it is simply a style issue or was there some deeper reason why it HAS TO be initialized in that function, instead of taking the other approach I described. (maybe availabilty of the object would not be there to call this in constructor or something ?)

No. Did you miss my post?

Definitely not. If the FObjectFinder isn’t static, then it is invoked for every call to the constructor. It’s “one time” for instances (though in truth, the constructor is not guaranteed to be called) but you’re still senselessly doing the same object find/load for each call to the constructor. If it is static, then it is invoked once (for the CDO) and the result persists for all instances.


void myobject::a()
{
	static ConstructorHelpers::FObjectFinder<UBlueprint> myJoyBP(TEXT("Blueprint'/Game/Characters/JoyGemBP.JoyGemBP'"));
	myJoyBP->DoThis();
}

The namespace “ConstructorHelpers” kind of gives it away, but this won’t work. FObjectFinders are meant to be used only in constructors. Try to use it outside of a constructor and it will raise an exception. You could instead use StaticFindObject/StaticLoadObject as FObjectFinder does internally, but then you would lose the entire point of this approach.

In UE4, constructors are meant to initialize the default object, not to construct instances. Instances are constructed from the default object, so in a way, the constructor will still indirectly construct instances. But in the case of loaded objects, the constructor can be skipped outright. In which case the only construction you get is from serializing the CDO as well as object values.

Strictly speaking, it is not necessary that this initialization be done for the default object (in the constructor). But a lot of things in the engine depend on the default object’s properties. This is why the object finder is static, but the member variable it assigns the object to is not. This way, whatever object or class was found using the object finder will be included in the CDO, allowing serialization and proper reference gathering for cooking.

-Camille

Your example/alternative is a little strange in that the FObjectFinder can only be used within a constructor, so I doubt you’d find anywhere in the engine/samples that duplicates the line as you have done in your myobject::a() and myobject::b().

There is absolutely nothing wrong with doing the following in the constructor


static ConstructorHelpers::FObjectFinder<UBlueprint> PlayerPawnOb(TEXT("Blueprint'/Game/Characters/JoyGemBP.JoyGemBP'"));
_myBP = PlayerPawnOb.Object;

and then accessing your _mpBP member later from multiple methods. That’s totally fine, if you need to store the pointer for later usage, then do so. However the FObjectFinder is used for just that - finding/loading the object. Whether you choose to then save the pointer in a member variable, or just use it once within the constructor, is not relevant. As has been said, the FObjectFinder variable is declared static to prevent the object lookup running more than once for a fixed path.

The line you suggested in your initial post would require the member variable to be of type FObjectFinder< UBlueprint >, rather than UBlueprint*. Maybe you meant this?


_someClassMember = ConstructorHelpers::FObjectFinder<UBlueprint>(TEXT("Blueprint'/Game/Characters/JoyGemBP.JoyGemBP'")).Object;

Regardless, either way this line would be executed every time an instance of your class were constructed, which is unnecessary.

Edit: Too slow. We need thread mutexes!

Truthfully… Yes :slight_smile: … I just saw Rama’s post and totally missed yours just above it.

Ok, agreed. In my mind I was thinking of the tutorials that had one object. But I see the point if you have this in an object that’s instantiated over and over and over again.

Gotcha - this is what I was looking for. I just downloaded unreal a couple of days ago and still figuring if some things are done a certain way because they have to be , or if they are simply a style/preference/performance thing .

Thanks!