"ConstructorHelpers::FObjectFinder" vs. "static ConstructorHelpers::FObjectFinder"

This seems like something super basic, but have never seen an explanation. All the asset loading examples I see have:

static ConstructorHelpers::FObjectFinder<SomeClass> … etc.”

but if I use that, every single mesh in the level becomes the same mesh (whichever is the first loaded). If I just call:

“ConstructorHelpers::FObjectFinder<SomeClass> … etc.” (no static)

Everything works correctly and all my meshes show up. What’s the difference?

3 Likes

For the record, here is my asset loading code. This snippet loads any class that extends StaticMeshComponent and attaches it to an actor:



/**
*   Add new interactive component to actor and a return a pointer to it.
*   New component must subclass SkeletalMeshComponent or StaticMeshComponent.
*
*  isRootComponent: Set component as root. Do this first and only once!
*  uniqueName: Unique name of object for simulation.
*  displayName: name displayed to player in mouse over, inventory, etc.
*  interactionType: NO_INTERACTION, INTERACTION_WHILE_WALKING, INTERACTION_MODE
*  socketName: Socket in root component to attach component to. Ignored if isRootComponent == true.
*  assetName: Name and path of static or skeletal mesh in content brower.
*/
template< class T > T*  AddInteractiveComponent(   bool isRootComponent,
						   FString uniqueName,
						   FString displayName,
						   InteractionType interactionType,
						   FName socketName,
						   const char* meshAssetName  )
{
	// create new component
	T* newMesh = CreateDefaultSubobject<T>(FName(*uniqueName));

	// if isRootComponent then set as root
        // else attach to designated socket in root component
	if (isRootComponent) RootComponent = newMesh;
        else newMesh->AttachTo(RootComponent, socketName);

	// new component is a static mesh so find mesh asset in game content
	if (newMesh->IsA(UStaticMeshComponent::StaticClass()))
	{
		ConstructorHelpers::FObjectFinder<UStaticMesh> newAsset(ANSI_TO_TCHAR(meshAssetName));
		if (newAsset.Succeeded())
		{
			((UStaticMeshComponent*)newMesh)->SetStaticMesh(newAsset.Object);
		}
		else
		{
			UE_LOG(MCS, Error, TEXT("%s: invalid static mesh component!"), *uniqueName);
		}
	}

	// new component subclasses an invalid class
	else
	{
		UE_LOG(MCS, Error, TEXT("%s: attempted to assign invalid asset as component!"), *uniqueName);
		return NULL;
	}

	// return pointer to new component
	return newMesh;

}


Ok, let’s look at this sample:



void MyClass::MyMethod()
{
    static ConstructorHelpers::FObjectFinder<UStaticMesh> staticAsset(TEXT("Path/To/StaticMesh"));
}


The keyword static makes the variable to be… ehm… static. This means it will have the same value every time you call a method. The exact value of variable is determined when method is called for the first time.
This is usefull for example when all instances of an actor should have a pointer to same shared asset. If you make such variable static, engine will search the asset only once - not every time the actor is spawned.
In your code you may need different asset references each time you call your method, so static is not needed.

8 Likes

There is better explanation of how “static” is works like. This is two examples:

#include <iostream>

void counter() {
  static int count = 0; // static!
  std::cout << count++;
}

int main() {
  for (int i = 0; i < 10; ++i) {
    counter();
  }
  return 0;
}

Output will be this: 0123456789
because static variables storeg “globally”. After function is executed static variable not getting destroyed. It’s very usefull trick.
If we not use static output of this code will be 000000000

#include <iostream>

void counter() {
  int count = 0; // non-static!
  std::cout << count++;
}

int main() {
  for (int i = 0; i < 10; ++i) {
    counter();
  }
  return 0;
}
2 Likes