Download

Component pointer changes between constructor and OnRegister call

Hello.

Could anyone help me understand how creation of components work?

Let’s say I have following component. Its purpose is to attach InstancedMeshComponent as child to Actor.



// WallComponent.h
class ARCHITECTURE_API UWallComponent : public USceneComponent
{
// basic stuff

protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = TestComp, meta = (AllowPrivateAccess = "true"))
UInstancedStaticMeshComponent* _instances;

}




// WallComponent.cpp

UWallComponent::UWallComponent() { UE_LOG(LogTemp, Warning, TEXT("UWallComponent constructor %s starts"), *name);
auto name = this->GetName();
name += FString("-wall");


_instances = CreateDefaultSubobject<UInstancedStaticMeshComponent>(*name);
_instances->SetupAttachment(this);
_instances->CreationMethod = EComponentCreationMethod::SimpleConstructionScript;

auto owner = GetOwner();
if (owner) {
  [INDENT=2]UE_LOG(LogTemp, Warning, TEXT("UWallComponent (%s): owner exists (%s)"), *this->GetName(), *owner->GetName());
UE_LOG(LogTemp, Warning, TEXT("UWallComponent (%s): _instances: (%s)"), *this->GetName(), *_instances->GetName()); // name is Wall-wall[/INDENT]
  }
 }

void UWallComponent::OnRegister()
{ Super::OnRegister();

if (_instances) {
  [INDENT=2]UE_LOG(LogTemp, Warning, TEXT("UWallComponent (%s): OnRegister _instances: %s"), *GetName(), *_instances->GetName()); // name is WallComponent_0-wall[/INDENT]
  }
 }

And Logs:


LogTemp: Warning: UWallComponent constructor Default__WallComponent starts
LogTemp: Warning: UWallComponent constructor WallComponent_0 starts
LogTemp: Warning: UWallComponent constructor Wall starts
LogTemp: Warning: UWallComponent (Wall): owner exists (TEST_ACTOR_BP_C_0)
LogTemp: Warning: UWallComponent (Wall): _instances: (Wall-wall)
LogTemp: Warning: UWallComponent (Wall): OnRegister _instances: WallComponent_0-wall

In logs I see:

  1. Constructor was called 3 times (might have something with CDO? But why not 2 times?)
  2. Value of **_instances **is changing between function calls:
  • in constructor was to **_instances **pointing to component with name **Wall-wall **(as I would expect)
  • inside function OnRegister is _instances pointing again to WallComponent_0-wall (also in other functions, so acessing **_instances **properties becames impossible)

Is there simple explanation for this behaviour? I could not find any resources explaing components lifecycle in depth.

Components cannot safely own (or be the Outer for) other Components, Compoents can only be owned by Actors. A lot of things will break if you don’t adhere to that rule. It definitely won’t work creating them in a constructor. You also won’t see them in the details panel, despite marking them with Edit/Visible Anywhere.

At best, you can override your “container” components’ OnRegister() function and and create additional components using it’s owning Actor as the outer through NewObject<>();

Thanks, TheJamsh that helped.

This is how my code looks now:



void UWallComponent::OnRegister()
{ Super::OnRegister();

auto name = this->GetName();
name += FString("-wall");

_instances = NewObject<UInstancedStaticMeshComponent>(GetOwner(), *name);
_instances->RegisterComponent();
_instances->AttachToComponent(this, FAttachmentTransformRules::KeepRelativeTransform);
_instances->CreationMethod = EComponentCreationMethod::Instance;

GetOwner()->AddInstanceComponent(_instances);
 

  }


Now I can access **_instances **property using BP or C++. Big step forward.
But in ClassDefaults in Blueprint editor I still see value as None.

Do I understand correctly that there is nothing I can do about it?