duke22
(duke22)
October 3, 2016, 11:24am
1
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;
}
trojanfoe
(trojanfoe)
October 4, 2016, 9:36am
2
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.
duke22
(duke22)
October 4, 2016, 11:07pm
3
Thanks for responding, I’ve added the actual code.
trojanfoe
(trojanfoe)
October 5, 2016, 6:23am
4
Ok in the BeginPlay method for-loop change auto to auto & and retry
scamp
(scamp)
October 7, 2016, 6:31am
5
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
mid_gen
(mid_gen)
October 7, 2016, 6:47am
6
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.
scamp
(scamp)
October 7, 2016, 6:58am
7
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
/hides from incoming c++ style war
mid_gen
(mid_gen)
October 7, 2016, 7:11am
8
well, it’s not the auto that’s the issue here. If the code was this you’d have the same problem
for (FTraffixSpawner Spawner : Spawners)
Spawner.Set(this);
scamp
(scamp)
October 7, 2016, 4:25pm
9
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.