#【概要】
「UE4では明示的な初期化をしなくても、メンバ変数はに0に初期化されるもの」
勝手にそう思い込んでいたが、実際そんなことはなく、理解が浅いまま危ない実装をしていたので、これを期にメンバ変数の初期化についてまとめてみた。
動作環境はUE4.24、VisualStudio 2019を使用。
#【公式ドキュメントを読んでみる】
まずは公式ドキュメントを読んでみる。
https://docs.unrealengine.com/4.26/ja/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Objects/Optimizations/
#####プロパティの自動初期化
コンストラクタが呼び出される前に、UObjects は初期化時に自動的にゼロになります。これはクラス全体、UProperties、ネイティブ メンバでも同様に起こります。
つまり、UObjectを継承したクラスのメンバ変数は、明示的に初期化をしていなくても、0に初期化されるということが分かった。
逆に言えば、UObjectを継承していないクラスや、構造体などのメンバ変数は、自動的に初期化されないことになる。
#【実践】
上記を踏まえた上で、実際にコードを書いてみる。
//UObjectを継承しないクラス
class Test
{
public:
Test(){};
bool BoolVal;
int32 IntVal;
float FloatVal;
class AActor* Ptr;
};
//UObjectを継承したクラス
UCLASS()
class UTest_UObject : public UObject
{
GENERATED_BODY()
public:
UTest_UObject(){};
bool BoolVal;
int32 IntVal;
float FloatVal;
class AActor* Ptr;
};
APlayer::BeginPlay()
{
//適当な場所でインスタンス生成
Test* TestPtr = new Test();
UTest_UObject* TestPtr_UObject = NewObject<UTest_UObject>(this, UTest_UObject::StaticClass());
UE_LOG(LogTemp, Log, TEXT("TestPtr BoolVal:%d, IntVal:%d, FloatVal:%.2f, Ptr:%d"), (int32)TestPtr->BoolVal, TestPtr->IntVal, TestPtr->FloatVal, TestPtr->Ptr);
UE_LOG(LogTemp, Log, TEXT("TestPtr_UObject BoolVal:%d, IntVal:%d, FloatVal:%.2f, Ptr:%d"), (int32)TestPtr_UObject->BoolVal, TestPtr_UObject->IntVal, TestPtr_UObject->FloatVal, TestPtr_UObject->Ptr);
}
実行結果
LogTemp: TestPtr BoolVal:96, IntVal:342, FloatVal:0.00, Ptr:6619236
LogTemp: TestPtr_UObject BoolVal:0, IntVal:0, FloatVal:0.00, Ptr:0
ドキュメント通り、UObjectを継承したクラスは全てのメンバ変数が0に初期化されたが、継承していないクラスは初期化されなかった。
#【初期化の方法】
明示的に初期化する方法はいくつかあるので、軽く触れておく。
class Test
{
public:
Test();
//一番最初に初期化される
int32 IntVal = 1;
};
Test::Test()
//初期化リスト。ヘッダーの次に初期化される。
:IntVal(2)
{
//初期化リストの次に初期化される。代入と同じなので負荷は他に比べて重い。
IntVal = 3;
}
#【結論】
初期化されなかった場合、元々メモリに存在していた値がその変数の値になる。
ローカル変数はメモリの書き換えが多いスタック領域に作られる為、初期化しないとゴミが入ることが多く、コンパイラによっては初期化しないとエラーになる場合がある。
ただし、ヒープ領域に作られるから大丈夫というわけではないので、明示的に初期化する習慣を付けることをオススメする。