UObject 의 Outer

2020. 3. 23. 03:09엔진/UE4

언리얼 오브젝트 ( 이하 UObject ) 를 생성 할 때 마주치는 것 중 하나가 Outer 라는 개념인데,

언리얼의 Outer 설명문구를 봐도 이해가 잘 안되었습니다.

 

Outer 란?

 생성중인 UObject 에 대한 Outer 로 설정할 UObject

Outer 의 사전적의미도 이해하기 좀 난해했습니다.

 

처음엔 어림잡아 '이 UObject  생성 시킨 녀석' 이라고 감이 올랑말랑 했던 기억이 있습니다.

그래서 샘플코드나 여러 책에서 this 포인터를 넣어주면 된다고 하지만, nullptr 을 지정하는 경우도 있고 무작정 this 를 넣기에는 영 찜찜했습니다.

 

UObject 생성 할 때 말고도 언리얼에서 제공하는 함수 중에 Outer 를 인자로 받는 것들이 많은데, 이 때도 this 를 넣는게 맞나? 하는 의문이 들며 관성적으로 this 를 넣기에는 불안했던 기억이 있습니다.

 

그래서 정확히 '어떤 목적을 위해서 Outer 를 지정하는지' 정리가 필요했습니다.

 

 

먼저 개인적으로 내린 Outer 의 정의는,

생성한 UObject 의 소유자 입니다.

 

이를 이해하기 위해서는 UObject 의 계층구조에 대해 먼저 살펴봐야 하는데요.

언리얼 UObject 의 근간은 World 로 부터 시작합니다.

 

World 가 있고, World 에 Level 이 있고, Level 에 Actor 가 있고, Actor 에 Component 가 있습니다.

그림으로 표현하자면 다음과 같이 표현 할 수 있습니다.

이런 식으로 부모-자식 관계를 갖게되는데, 여기서 부모가 Outer 라고 보면 됩니다.

 

 

실제 예를 통해 살펴보면,

UE4 의 ACharacter 는 CharacterMovementComponent, SkeletalMeshComponent 를 가지고 있는데 이미 짐작하셨듯

ACharacter 가 두 Component 의 Outer 입니다.

  • ACharacter
    • CharacterMovementComponent
    • SkeletalMeshComponent
ACharacter::ACharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
	...
	
    CharacterMovement = CreateDefaultSubobject<UCharacterMovementComponent>(ACharacter::CharacterMovementComponentName);
	Mesh = CreateOptionalDefaultSubobject<USkeletalMeshComponent>(ACharacter::MeshComponentName);
	
    ...
}

ACharacter 의 생성자에서 CreateDefaultSubobject() 를 호출하여 두 Component 를 생성하고 있는데요.

문득 this 는 어디갔어? 라고 할 수 있지만, CreateDefaultSubobject() 내부에서 this 를 넣어주고 있기 때문에

CharacterMovement 와 SkeletalMesh 컴포넌트는 모두 ACharacter 를 Outer 로 갖게 됩니다.

 

 

언리얼 오브젝트는 생성자 안에서 CreateDefaultSubobject() 를 통해 생성 할 수도 있지만, 생성자 밖에서 NewObject() 로도 생성 할 수 있습니다. ( 생성자 안에서는 NewObject() 를 호출 할 수 없습니다. 이 반대도 마찬가지입니다. )

CreateDefaultSubobject() 와는 달리 NewObject 는 명시적으로 Outer 를 지정해주어야 합니다.

 

저같은 경우엔, 이 때부터 this 를 할지, nullptr 을 할지, 아니면 객체 포인터를 직접 넘겨야하는지 고민이 되었었습니다.

 

Outer 를 왜 지정해줘야 하지?

결론부터 얘기하자면 언리얼의 GC ( Garbage Collection ) 를 방지하기 위해서 인데요.

언리얼의 GC 는 철저히 Reflection 을 기반으로 이루어지기 때문에 동적으로 생성되는 객체들이 어떤 참조 관계를 갖게되는지 알 수 없습니다.

 

이 때문에 멤버 변수로 UObject 를 가지게 되는 경우에도, 꼭 UProperty() 매크로를 지정해주어야 한다고 경고합니다.

 

 

 

 

 

 

https://wiki.unrealengine.com/Garbage_Collection_Overview

https://wiki.unrealengine.com/Garbage_Collection_%26_Dynamic_Memory_Allocation

https://wiki.unrealengine.com/Garbage_Collection_~_Count_References_To_Any_Object#Code

https://docs.unrealengine.com/en-US/API/Runtime/CoreUObject/UObject/UObject/Rename/index.html

'엔진 > UE4' 카테고리의 다른 글

Blueprint 에서 지원하는 UPROPERTY type  (0) 2020.05.18
UE4 GitHub 으로 설치하기  (0) 2020.05.11