Tick ignoring variables set in BeginPlay

Say I have the following piece of code:


void ASomeActor::BeginPlay()
{
	Super::BeginPlay();
	
	SomeObject->SomeDependency = this;
}

void ASomeActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
	auto o = SomeObject->SomeDependency;
}

o is NULL.

For now I’m setting them in Tick instead (using a bFirstTick flag) but this seems hacky. Is there a reason this happens or a cleaner way to solve it?

The actual code is:


// UTraffixSimulationComponent HEADER
UCLASS(BlueprintType)
class UTraffixSimulationComponent
	: public USceneComponent,
	public FTraffixTickable
{
	GENERATED_BODY()

public:
	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Simulation")
	TArray<FTraffixSpawner> Spawners;

	virtual void BeginPlay() override;
	virtual void TickTraffix(const float& InDeltaTime, const int32& InLODLevel = 0) override;
	virtual void BeginDestroy() override;

private:
	bool bFirstTick;
};

// UTraffixSimulationComponent CPP
void UTraffixSimulationComponent::BeginPlay()
{
	Super::BeginPlay();

	for (auto Spawner : Spawners)
		Spawner.Set(this);
}

// FTraffixSpawner HEADER
USTRUCT(BlueprintType)
struct FTraffixSpawner
{
	GENERATED_BODY()

public:
	UPROPERTY(Transient)
	UTraffixSimulationComponent* Simulation;

public:
	void Set(UTraffixSimulationComponent* InSimulation);
};

// FTraffixSpawner CPP
void FTraffixSpawner::Set(UTraffixSimulationComponent* InSimulation)
{
	Simulation = InSimulation;
}

There is no reason that won’t work, but could you show us the real code as it’s not clear if SomeObject is a member variable or retrieved from somewhere else.

Thanks for responding, I’ve added the actual code.

Ok in the BeginPlay method for-loop change auto to auto & and retry

I think you’re getting what I’ve seen from time to time: Tick() gets called before BeginPlay(). Haven’t tracked down exactly why that happens but I’d love to know if there’s a way to guarantee BeginPlay() before any Tick()s.

Slightly cleaner version just checks for nullptr inside Tick(), but yeah, still ugly I agree.

Sometimes i’ll hook up a timer function which just does initialization like this, then stops itself once everything is ready. Also ugly though :frowning:

This. You (almost) never want to use objects by value inside a for loop.


// UTraffixSimulationComponent CPP
void UTraffixSimulationComponent::BeginPlay()
{
	Super::BeginPlay();

	for (auto Spawner : Spawners)
		Spawner.Set(this);
}

This code is creating a copy of each FTraffixSpawner in the Spawners array and calls the set method. The copied Spawner then goes out of scope and disappears.


// UTraffixSimulationComponent CPP
void UTraffixSimulationComponent::BeginPlay()
{
	Super::BeginPlay();

	for (auto& Spawner : Spawners)
		Spawner.Set(this);
}


This code calls the set method on each Spawner in the Spawners array.

Tip : By default, USTRUCTS are deep copied on when assigned.

Ahh yes, the 'ol “auto” inside the for-each loop. Think everyone gets burned by this when using C++11. I know I did…

Solution: Don’t use auto. Then your code is more readable and you won’t run into this issue :slight_smile:

/hides from incoming c++ style war

well, it’s not the auto that’s the issue here. If the code was this you’d have the same problem :slight_smile:


for (FTraffixSpawner Spawner : Spawners)
		Spawner.Set(this);

Yeah, my point though is about the amibiguity of “auto”.

Should auto include the pointer automatically? If it did, then it would work. Since it doesn’t, it’s added confusion.

with FTraffixSpawn Spawner : Spawner, it’s obvious you have a copy.