언리얼 C++ RTTI 심층 분석

왜 언리얼 엔진은 표준 C++ RTTI를 사용하지 않고 자체 리플렉션 시스템을 구축했을까?

표준의 길을 벗어난 이유

언리얼 엔진은 성능, 메모리, 그리고 엔진 시스템과의 깊은 통합을 위해 표준 C++ RTTI를 의도적으로 비활성화합니다. 이는 단순한 회피가 아닌, 게임 엔진에 최적화된 환경을 구축하기 위한 전략적 선택입니다.

성능 저하 방지

표준 `dynamic_cast`는 복잡한 상속 구조에서 상당한 런타임 오버헤드를 유발할 수 있습니다. 언리얼은 더 빠르고 예측 가능한 타입 검사를 선호합니다.

💾

메모리 및 용량 최적화

RTTI는 모든 가상 클래스에 타입 정보를 추가하여 바이너리 크기와 메모리 사용량을 증가시킵니다. 대규모 엔진에서는 이 부담이 상당합니다.

🧩

엔진과의 완벽한 통합

에디터, GC, 직렬화, 블루프린트와 같은 핵심 기능들은 표준 RTTI가 제공하는 것 이상의 상세한 메타데이터를 요구합니다.

언리얼의 해답: 리플렉션 시스템

언리얼은 C++ 소스 코드를 분석하여 런타임에 필요한 타입 정보를 생성하는 독자적인 리플렉션 시스템을 구축했습니다. 이 과정의 중심에는 언리얼 헤더 툴(UHT)이 있습니다.

1. C++ 헤더 파일

`UCLASS`, `UPROPERTY` 등
리플렉션 매크로 포함

2. 언리얼 헤더 툴 (UHT)

매크로를 파싱하여
메타데이터 추출

3. *.generated.h 생성

리플렉션 데이터가 담긴
C++ 코드 자동 생성

4. 컴파일

원본 코드와 함께 컴파일되어
실행 파일에 포함

언리얼 스타일 타입 캐스팅

언리얼은 `dynamic_cast`를 대체하는 안전하고 효율적인 자체 캐스팅 함수들을 제공합니다. 이 함수들은 모두 `UObject` 기반 클래스에서 작동합니다.

함수 역할 실패 시 반환 주요 사용 사례
Cast<T> 타입 안전 동적 다운캐스팅 nullptr 가장 일반적인 형태의 안전한 캐스팅
IsA<T> 객체가 특정 타입인지 확인 false (bool) 캐스팅 없이 타입만 검사할 때
ExactCast<T> 정확한 타입 일치 여부 확인 후 캐스팅 nullptr 타입이 완전히 동일함을 알 때 사용하는 고효율 캐스팅
CastChecked<T> 성공을 확신하는 상황에서의 캐스팅 어설션/크래시 캐스팅 실패가 프로그래머 오류일 때

성능 비교: 두 빌드의 이야기

언리얼의 캐스팅 성능은 빌드 구성에 따라 달라집니다. 에디터 빌드에서는 디버깅을 위해 상세 정보를 유지하지만, 배포(Shipping) 빌드에서는 압도적인 속도를 위해 최적화됩니다.

위 차트는 상속 깊이가 증가함에 따른 캐스팅 연산 비용의 변화를 보여줍니다. 배포 빌드에서의 상수 시간(O(1)) 복잡도는 언리얼 캐스팅의 핵심적인 성능 우위입니다.

리플렉션의 막강한 이점

언리얼의 리플렉션 시스템은 단순한 타입 검사를 넘어, 엔진의 핵심 기능들을 떠받치는 기둥 역할을 합니다.

🖥️에디터 통합

`UPROPERTY` 매크로 하나로 C++ 변수를 에디터의 디테일 패널에 노출시키고 실시간으로 수정할 수 있습니다.

💾자동 직렬화

리플렉션 시스템이 `UObject`의 프로퍼티를 인지하여, 게임 저장/로딩 시 데이터를 자동으로 기록하고 복원합니다.

🗑️강력한 가비지 컬렉션

객체 간의 참조를 추적하여 더 이상 사용되지 않는 `UObject`를 자동으로 메모리에서 해제하고, 댕글링 포인터를 방지합니다.

🧩블루프린트 연동

`UFUNCTION`, `UPROPERTY` 등으로 C++ 코드와 블루프린트 비주얼 스크립팅을 매끄럽게 연결하여 협업 효율을 극대화합니다.

🔄프로퍼티 자동 업데이트

부모 클래스나 CDO(Class Default Object)의 기본값이 변경되면, 이를 상속받는 객체들의 프로퍼티를 지능적으로 업데이트합니다.

🔌동적 확장성

런타임에 타입을 식별하는 통일된 방법을 제공하여, 플러그인과 같은 모듈식 아키텍처를 안전하게 지원합니다.