Download

Problem with declaring member variables in header files

I’m having a problem where I run into unexpected behaviour if I change the order in which the member variables in one of my classes are declared in the header file.

First off, I’m a Java programmer, and I’ve just recently started delving into C++, so I apologize in advance for any mistakes I make regarding the naming conventions in the C++ language. Please bear with me if I’m not using all the correct terms.

I started working through the FloatingActor example found at https://docs.unrealengine.com/latest/INT/Programming/QuickStart/4/index.html. I attached a component to my actor, and everything worked like a charm. My actor was floating, bobbing up and down!

I decided I wanted to expand this code a bit, so I added a couple of uproperties which allows you to determine how far the component would float and in which direction. I also added a couple of member variables that stores the components initial x and z values.

The issue I encounter is the following: If I rearrange the order in which the member variables are declared in the header file, the components attached to the actor won’t move. I get no errors or exceptions as far as I can tell, the code just doesn’t work as intended any more for some reason.

The .cpp code looks like this:



#include "Brawler25D.h"
#include "FloatingSineWaveActor.h"

// Sets default values
AFloatingSineWaveActor::AFloatingSineWaveActor() : StartLocationX(0.0), StartLocationZ(0.0), HorizontalMovement(false), FloatDistance(0.0), RunningTime(0.0)
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AFloatingSineWaveActor::BeginPlay()
{
	StartLocationX = GetActorLocation().X;
	StartLocationZ = GetActorLocation().Z;
	Super::BeginPlay();
}

// Called every frame
void AFloatingSineWaveActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	RunningTime += DeltaTime;
	FVector NewLocation = GetActorLocation();
	if (HorizontalMovement) {
		NewLocation.X = StartLocationX + ((FMath::Sin(RunningTime) + 1.0) * 0.5 * FloatDistance);
	} else {
		NewLocation.Z = StartLocationZ + ((FMath::Sin(RunningTime) + 1.0) * 0.5 * FloatDistance);
	}
	SetActorLocation(NewLocation);
}


And the header file:



#pragma once

#include "GameFramework/Actor.h"
#include "FloatingSineWaveActor.generated.h"

UCLASS()
class BRAWLER25D_API AFloatingSineWaveActor : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AFloatingSineWaveActor();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UPROPERTY(EditAnywhere)
		bool HorizontalMovement;
	UPROPERTY(EditAnywhere)
		float FloatDistance;
	float RunningTime;
	float StartLocationX;
	float StartLocationZ;
};


When the member variables are sorted in the order they are above, everything works!
The code silently breaks, however, if I sort them like this:



public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	float RunningTime;
	UPROPERTY(EditAnywhere)
		bool HorizontalMovement;
	UPROPERTY(EditAnywhere)
		float FloatDistance;
	float StartLocationX;
	float StartLocationZ;


I’ve tried ordering them several ways to see if I could find a pattern of sorts, but I can’t say I have. Also, I may have misunderstood something, but isn’t part of the reason why header files exists to give you a way of declaring functions and member variables without worrying about the order in which you declare them? I thought maybe it was related to uproperties being declared first or last, but that doesn’t seem to add up either when testing different orders…

I’ve thoroughly searched for information about this issue, but I can’t seem to find anything related. I’m also not sure if I’m using the right terms while searching, which isn’t helping. Any feedback would be greatly appreciated!

You’re not setting the initial values of those member variables; so I believe their initial values are just random junk.

Set the initial values of the member values in the constructor and I believe that should resolve your issue.

Thanks for the reply! This is the same tip I got from someone earlier actually, and I thought I already did so. Am I not initializing the member variables already with the first line of the constructor?


// Sets default values
AFloatingSineWaveActor::AFloatingSineWaveActor() : **StartLocationX(0.0), StartLocationZ(0.0), HorizontalMovement(false), FloatDistance(0.0), RunningTime(0.0)**
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

Ahh okay sorry didn’t notice that. I tend to initialize on new lines :slight_smile:

That’s the only cause that comes to mind… other than perhaps it’s just not using the latest compiled version. Have you tried pressing the “Compile” button in the UE4 editor toolbar. I’ve noticed a few situations where simply building in Visual Studio hasn’t propagated to UE4 until I’ve also pressed “Compile” in there.

I’ve been building in VS between plays, and I see the difference when playing from build to build, so I’d be surprised if that wasn’t working properly. Just now tested compiling via the Unreal Editor just to be sure, and the problem persists.

The more testing I do, the more it feels like this may be an issue with having to define UPROPERTY()s before other member variables. Could that be a thing, or am I way off now? :slight_smile:

When you say the code silently breaks… what does it do or not do?

If you add some logging statements (or do an editor debug build with breakpoints); what kind of values are you seeing?

I believe I found the problem, and the header files aren’t the actual culprits… hot realoading is! (i think… :-))

The issue seems to be related to building and hot reloading, as Kruncher pointed out as a possibility in an earlier reply. (thanks for pointing me in that direction) It looks like when I build my c++ project WHILE the unreal editor is open (either from VS2015 or hitting compile in the editor), the hot reload doesn’t recognize that there are changes when I change the order of member variables in the header. Maybe this creates a mismatch with the member variables in the actual VS build and in UE, and that is causing my game to have unexpected behaviour? In other words, when I decide to clean up the code in my header file (which includes moving stuff around) and then hit the compile button, all of a sudden my actor doesn’t work (or in some cases it works somewhat, but not really as intended). If I revert the header file back to the state where it worked and hit compile, everything works properly again, but the hot reload will once again tell me no changes were detected…

I can work around this by simple closing the unreal editor and running/debugging my game from VS2015, relaunching the unreal editor from there. I guess this makes sure the unreal editor is 100% up to date since it then does a full reload instead of a hot reload?

So I have a workaround, but it feels clunky having to relaunch the editor all the time, especially since I have the big compile button in the editor that just wants to be pressed… :slight_smile: I guess my follow up questions are:

  • Is there a workflow I should follow to avoid ending up in a situation where VS and the UE editor are out of sync?
  • Are there other, known cases where the hot reload will fail to recognize changes?
  • Is there a way to force the hot reload recognize changes in a particular file?

General rule of thumb I found… don’t use hot reload if you change any headers at all. It doesn’t work.

I started reading through this thread thinking that the order of the variables in your ctor initialization list might be causing issues, becase the order there does matter (depends on compiler really but better safe than sorry).

Then I read that it was hot reload. It is always hot reload. Hot reload never works.

From what you guys are saying, it sounds like another good rule of thumb would be to always do a full reload to see if the hot reload is the culprit when your game doesn’t work the way you expect after code changes… (and you see no obvious errors)

Not really the answer I was hoping for, but at least it’s a problem you can work around as long as you are aware of it!

Although the problem has already been solved, just to add to this so nobody gets confused (and maybe that’s what you meant but it sounds different): The order of the variables in the ctor initialization list does NOT matter. The member variables are always initialized in the order they are declared in the header file (so by changing the order there as op said, the initialzation order does indeed change, just like you said, that’s also what first came to my mind). At least that is what the standard says and there are good reasons for this (there might be multiple constructors but only one destrcutor, which destroys the member variables in reverse order of the class definition [also see here: c++ - Constructor initialization-list evaluation order - Stack Overflow]). You already said it depends on the compiler but I don’t see a reason why a “normal” compiler would do it differently.
Maybe it is different in UE4 as there is usually (normally/always?) only one constrcutor but I see no reason why one should explicitly differ from the standard then. Maybe you have mor infos on this if it does indeed differ?

Eh, I just know that in the past the initialization list in a ctor had to go in the same order as the variables are declared in, otherwise it could cause issues. It is most likely that 99.99% of compilers worth their salt won’t have that issue anymore, but I like to be better safe than sorry. It’s tidier anyway.

That’s definitely true but I think it’s worth knowing that the initializer lists order is not the one that is used as that’s not necesseraily what you’d expect in the first place when learning C++ or being new to it. Might save a lot of headache, especially when initializing members that depend on each other.

So the best feature of UE4 is useless?

This; before finish reading I was just saying that lol

Can’t really be the best feature if it doesn’t work :smiley: