Download

Actor's Uproperty contains null pointer after begin BeginPlay

HI there! I’m new in UE and C++ in general (btw have a lot experience in Java). I have issues with null pointers when I add my character to editor and start playing. I created several logs of actor initialization and it confused me even more.

TacticalCharacter.h

class ATacticalCharacter : public ACharacter
{
	GENERATED_BODY()
public:
	ATacticalCharacter();

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Attributes")
	UCharacterAttributes* Attributes;
	...

TacticalCharacter.cpp

ATacticalCharacter::ATacticalCharacter()
{
	Attributes = NewObject<UCharacterAttributes>(this, TEXT("Attributes"));
	Attributes->Name = GetName();
	UE_LOG(LogTemp, Warning, TEXT("Actor created %s Attributes is set %d"), *(Attributes->Name), (Attributes)?1:0);
	assert(Attributes);
}

CharacterAttributes.h

UCLASS()
class UCharacterAttributes : public UActorComponent
{
	GENERATED_BODY()
public:
	FString Name;
	virtual void BeginDestroy() override;

Also I create Blueprint from TacticalCharacter
When I start dragging TacticalCharacter Blueprint to map in editor I have following in the logs:

LogTemp: Warning: Actor created TacticalCharacterPlayer_BP_C_3 Attributes is set 1
LogTemp: Warning: Actor created TacticalCharacterPlayer_BP_C_4 Attributes is set 1

When I press Play and put breakpoint to line: Attributes = NewObject(this, TEXT(“Attributes”));
I can see properly initialized object for actor with name TacticalCharacterPlayer_BP_C_5 (why 5?)
Next breakpoint in UCharacterAttributes ::BeginDestroy. I can see that Attributes is destoryed only for TacticalCharacterPlayer_BP_C_3

Next breakpoint in TacticalCharacter::BeginPlay where Attributes is null now.
Why this happens? Why is object created so many times? I haven’t seen that Attributes for TacticalCharacterPlayer_BP_C_5 was destroyed (at least BeginDestroy was not called)

Will be appreciated for any help

You shouldn’t create objects in your constructor. Try using BeginPlay() or PostInitializeComponents().

What happens during object construction in UE4 is a whole mystical process to me, and there are tons of threads of people trying to understand it. If you want, I suggest you look into Unreal’s reflection system, how CDOs work, and look into threads trying to demystify the whole process.
Or just use BeginPlay() and leave it for another day.

AActor::OnConstruction() is the native version of the construct script in blueprints, but this case doesn’t seem to want that.

I kept this bookmarked since I was confused by this when I was starting out as well:

UObjects shouldn’t have a specifier of the “Edit” variety either. You should be using VisibleDefaultsOnly.

This video goes through it nicely too.

Thx a lot for reply. I don’t understand why so many tutorials are using constructor to initialize properties. Also in my case a lot of properties work fine, except mine created one. For example

FullPathSpline = CreateDefaultSubobject<USplineComponent>(TEXT("FullPathSpline"));
AddedSplineMeshComponents.Empty();
CaptureComponentHead = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("CaptureComponentHead"));
CaptureComponentHead->CaptureSource = SCS_FinalColorLDR;
CaptureComponentHead->bCaptureEveryFrame = false;	
	
FString asd = GetName();
UTextureRenderTarget2D* renderTarget = NewObject<UTextureRenderTarget2D>(this, *asd);
renderTarget->InitAutoFormat(512, 512);
renderTarget->UpdateResourceImmediate();
CaptureComponentHead->TextureTarget = renderTarget;
CaptureComponentHead->UpdateContent();

All of these properties work fine. Although I have issues now with USceneCaptureComponent2D. If I create UTextureRenderTarget2D in constructor if works, but UE uses same instance for all actors. If I move it to BeginPlay, I have separate UTextureRenderTarget2D for each actor but nothing works… I have only black image in that case.

As I understand from lifecicle PostInitializeComponents is more proper place to init objects, because BeginPlay - Called when the level is started and for complex init I would have fps lose on startup, right?

PS
I’ve tryed to move

CaptureComponentHead = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("CaptureComponentHead"));

to PostInitializeComponents and BeginPlay and catch the error

Fatal error: [File:D:/Build/++UE4/Sync/Engine/Source/Runtime/CoreUObject/Private/UObject/Obj.cpp] [Line: 112] No object initializer found during construction.

UE4Editor_CoreUObject
UE4Editor_Tactical!ATacticalCharacterPlayer::PostInitializeComponents() [D:\Games\Tactical\Source\Tactical\TacticalCharacterPlayer.cpp:82]

When in case of cunstructor all works fine. I don’t understand what should I move to constructor and to PostInitializeComponents/BeginPlay. What is the rule to take this decision )

PostInitializeComponents() and BeginPlay() are both called when the game is started so both will hit performance the same. I wouldn’t worry about that unless you’re doing something incredibly long or have a ton of instances created all at the same time.

You should use CreateDefaultSubobject() in the constructor, not BeginPlay(). Components are usually created in the constructor, objects that should be spawned in editor go into OnConstruction() (such as spawning mesh along a spline to create pipes in a level), and all other objects should be created at runtime such as BeginPlay().