언리얼로 개발을 하다보면 코드에 굉장히 많은 캐스팅 함수를 볼 수 있을 것이다.
이는 언리얼뿐만 아니라 객체지향식으로 코드를 짜다보면 당연히 일어나게 되는 경우고, 특히나 계층구조를 중요시 여기는 언리얼에서는 Casting없이는 코드를 짜는게 불가능한 수준이다.
당장 멀리 안가고, 레포에 있는 내 코드만 살펴보더라도 매 코드나 함수마다 initialization 혹은 Casting을 반복해서 선언하게 된다.
당연하게도, Casintg같은 연산은 성능에 많은 코스트를 소모함으로 자주 사용하게 되면 성능저하가 일어나게 된다.
이때 필요한것이 Lazy Initialization이다.
직역하면 지연 초기화란 뜻이다.
필요할 때 객체를 생성하거나 초기화하지 않고, 실제로 사용할 때 처음 한번만 초기화 하는것을 뜻한다.
이게 무슨소리냐. 글자만 보면 잘 이해가 되지 않을 수 있다.
아래의 코드를 살펴보자.
void AWeapon::Fire()
{
Ammo--;
ABlasterCharacter* Character = Cast<ABlasterCharacter>(GetOwner());
if (Character)
{
ABlasterPlayerController* Controller = Cast<ABlasterPlayerController>(Character->Controller);
if (Controller)
{
Controller->SetHUDWeaponAmmo(Ammo);
}
}
}
해당 조건에 맞게 접근한 코드이다.
총알의 숫자를 줄이며 Character와 Controller의 두차례 캐스팅을 통해 함수를 호출한다.
void AWeapon::Fire()
{
Ammo--;
SetHUDAmmo();
}
void AWeapon::SetHUDAmmo()
{
if (BlasterOwnerCharacter == nullptr)
{
BlasterOwnerCharacter = Cast<ABlasterCharacter>(GetOwner());
}
if (BlasterOwnerCharacter && BlasterOwnerController == nullptr)
{
BlasterOwnerController = Cast<ABlasterPlayerController>(BlasterOwnerCharacter->Controller);
}
if (BlasterOwnerController)
{
BlasterOwnerController->SetHUDWeaponAmmo(Ammo);
}
}
Fire()함수에 본 목적을 두고, SetHUDAmmo()함수를 새로 만들어 캐스팅과정을 반복하였다. 여기까지 보면 똑같이 캐스팅 2번하는거 아닌가? 할 수 있지만 Cast연산은 초기에 한번만 실행한다.
또한 안정성을 위해 nullptr check를 통해 캐스팅을 생략한다. 즉 반복적인 Cast과정을 제거하고 이를 구조화 시킨 코드이다.
그리고 여기서 조금(?)만 더 나아가 삼항연산자를 활용하면 코드를 더 줄일 수 있다.
void AWeapon::SetHUDAmmo()
{
BlasterOwnerCharacter=BlasterOwnerCharacter==nullptr?Cast<ABlasterCharacter> (GetOwner()) : BlasterOwnerCharacter;
if (BlasterOwnerCharacter)
{
BlasterOwnerController=BlasterOwnerController==nullptr?
Cast<ABlasterPlayerController>(BlasterOwnerCharacter->Controller):BlasterOwnerController;
if (BlasterOwnerController)
{
BlasterOwnerController->SetHUDWeaponAmmo(Ammo);
}
}
}
Chracter가 nullptr, 그러니까 초기상황처럼 어떤 캐릭터도 해당 OwnerCharacter 포인터에 할당되지 않은 경우만 캐스팅을 실행한다.
Controller도 이와 같이 nullptr일 때만 해당 캐스팅을 실행하게 되고, 그렇지 않으면 기존의 컨트롤러를 가져가서 아래의 SetWHUDWeaponAmmo()함수를 실행하게 된다.
이처럼 Lazy Initialzation을 하는 것 만으로 캐스팅을 줄일 수 있고, 이는 성능향상으로 이어진다.