목록Categories (1104)
KoreanFoodie's Study

언리얼의 Cast 동작 원리 핵심 1. Cast 는 UObject 에 쓰여야 한다. Cast 는 static_cast 와는 달리 타입 안정성을 지닌다(nullptr 를 리턴). 2. Cast 의 런타임 비용은 에디터 환경에서는 O(O(Depth(InheritanceTree))) 이고, 에디터가 아닐 때는 O(1) 이다. 3. Cast 는 dynamic_cast 를 사용하지 않는다. dynamic_cast 대신 Cast 를 사용하라! 실제로 언리얼의 Cast 는 다음과 같이 구현되어 있다 : // Dynamically cast an object type-safely. template FORCEINLINE To* Cast(From* Src) { return TCastImpl::DoCast(Src); } 내부..

UObject 의 클래스 타입 체크 (런타임) 우리가 아이템을 사용하는데, 소모품일 경우 수량을 깎는 코드를 짠다고 가정해 보자. 코드는 다음과 같다. if (nullptr != Cast(myItem)) { this->consumeItem(myItem); } else { this->useItem(myItem); } (물론 현실적으로 이런 경우, FConsumable 클래스에서 useItem 을 override 하겠지만.. 여튼) 위처럼, 객체의 클래스 타입을 체크하는 경우, 어떻게 하는 것이 효율적일까? 위와 같은 경우에, 만약 캐스팅이 실제로 필요한 경우가 아니라면(즉, 그냥 타입 체킹만 하면 되는 경우라면), Cast(언리얼의 Cast 는 업/다운 캐스팅을 할 수 있도록 구현되어 있다)를 쓰는 것보다..

텍스트 조회 보통 프로젝트 규모가 커지게 되면, 각종 스트링들을 스트링 테이블에 넣어서 사용할 것이다. 이때 스트링 테이블은 Namespace 와 키 값 두 개가 있고, 원하는 Namespace 에서 키를 대입해 원하는 텍스트를 찾게 된다. Namespace 는 간단히 말해 스트링 테이블 파일의 이름이라고 보면 된다. 실제로 C++ 코드로 짜면, 다음과 같다 : FText findText; FText::FindText(TEXT("your_namespace"), TEXT("your_key"), findText); your_namespace 와 your_key 에 적합한 값을 주면, 원하는 값이 findText 에 들어갈 것이다. 아참, 스트링 테이블을 만든 다음, 상단의 '네임스페이스' 를 제대로 설정해 ..

Delay 실행 만약 일정 시간이 지난 후 함수가 실행되길 원한다면, FTimerHandle 을 이용해 다음과 같이 코드를 짜면 된다. FTimerHandle myTimerHandle; GetWorld()->GetTimerManager().SetTimer(myTimerHandle, FTimerDelegate::CreateLambda([&]() { // 내가 원하는 코드 구현 DoSomething(); // 타이머 초기화 GetWorld()->GetTimerManager().ClearTimer(fadeOutTimerHandle); }), InDelayTime, false); // 반복 실행을 하고 싶으면 false 대신 true 대입 아, 참고로 FTimerHandle 은 글로벌 타이머 매니저에서 사용하며..
이 병은 예고도 없이 찾아온다. 한 번 왔다고 해서 다시 찾아오지 않는 것도 아니며, 이미 겪어 보았다고 해서 더 견디기 쉬워지는 것도 아니다. 그냥 공허함이 내 몸속을 파고든다. 햇살의 줄기, 그 속에 담긴 입자 하나하나가 내 몸 속 깊은 곳까지 파고들듯이, 공허의 알갱이들은 깊숙히 내 속으로 휘몰아친다. 나는 그 녀석이 올 때마다, 곧 넘쳐 흐를 것만 같이 부글거리는 냄비를 든 아이처럼 어쩔 줄을 몰라 한다. 따뜻해야만 할 가족들의 웃음소리가 마치 싸구려 골판지가 우그러지는 소리처럼 느껴지고, 사랑하는 사람과 함께한 시간은, 마치 대여기간이 정해진 소꿉놀이처럼 느껴지게 만드는 불치병. 지독한 병을 조금이라도 달래기 위해, 환자는 오늘도 연인의 시간을 빌려쓰려 휴대폰을 들어 밝은 목소리를 꾸며낸다.

inline 과 FORCEINLINE 의 차이 사실 이 둘의 차이는 이미 단어에서 쉽게 파악할 수 있다. 일단 함수의 인라인화라는 것은, 컴파일러가 함수 바디를 컴파일 타임에 붙여 넣어 함수 호출의 오버헤드를 줄이는 최적화 방식이라고 볼 수 있다. C++ 에서 inline 은 컴파일러에게 함수를 인라인화할 것을 '요청' 한다. 이는 '명령' 이나 '강제'가 아니다. 복잡한 함수나 가상함수는 컴파일러가 인라인화 해주지 않으며, inline 키워드를 쓰지 않더라도 작고 간단한 함수의 경우 컴파일러가 알아서 인라인화를 해 주기도 한다. 반면 FORCEINLINE 은 말 그대로 강제적으로 인라인화를 시킨다. 생성자와 소멸자 등, 인라인화 시키기에 적합하지 않은함수들이 생각보다 많이 존재하므로, FORCEINLI..

C++ 에 대해 공부한 것과, 개발하면서 알게 된 것들을 다룹니다 RTTI RTTI 는 간단히 말해, 실시간 타입 정보라는 뜻이다. RTTI 라는 단어를 평소에는 잘 들어볼 일이 없다가, dynamic_cast 를 사용하기 위해 비주얼 스튜디오 옵션을 뒤적이던 중 해당 항목을 발견했다. 알다시피, C++ 는 리플렉션 기능을 제공하지 않는다. C# 에서는 리플렉션을 제공하는데, 해당 기능은 런타임에서 클래스 타입, 메소드, 프로퍼티 등의 메타 정보를 제공해 준다. 비주얼 스튜디오에서는 해당 기능을 끄고 킬 수 있게 만들어 놓았다. 간단히 말해, 해당 기능을 키게 되면 런타임에서 타입에 대한 정보를 얻을 수 있다. RTTI 는 가상 함수가 있는 클래스에 대해서만 동작하며, 이는 클래스의 타입 관련 정보가 v..

C++ 에 대해 공부한 것과, 개발하면서 알게 된 것들을 다룹니다 파생 클래스에서의 기반 클래스 생성자 호출 사실 파생 클래스가 생성될 때, 기반 클래스 생성자가 호출된다는 건, C++ 을 조금이라도 해 본 사람은 누구나 알고 있는 사실이다. 또한 함수의 생성자/소멸자의 호출 순서가 다음과 같다는 것도, 익히 알려진 사실이다. 즉, A 클래스가 기반 클래스이고, B 클래스가 파생 클래스라고 가정했을 때 B 클래스 변수를 선언하면 호출 순서가 다음과 같이 나올 것이다 : A 클래스 생성자 B 클래스 생성자 B 클래스 소멸자 A 클래스 소멸자 하지만 한 가지 기억해야 할 것은, 파생 클래스를 만들 때 호출되는 기반 클래스 생성자는 '인자가 없는 기반 클래스의 생성자' 이다. 즉, 인자를 받는 형식의 기반 클..

C++ 에 대해 공부한 것과, 개발하면서 알게 된 것들을 다룹니다 우측값과 좌측값 우리는 C++03 까지, 우리는 우측값과 좌측값 두 가지의 개념을 사용하여 코딩을 했었다. 간단히 말하자면, 좌측값은 '식의 좌측에 있는 변수'를, 우측값은 '식의 우측에 있는 값'을 의미했다. // a 는 좌측값, 5 는 우측값이다 int a = 5; 흔히들 좌측값을 '이름이 있는 녀석'으로 인식하기도 했다. 엄밀히 말하면 틀린 말은 아니다. 그런데 move semantics 가 도입되기 시작하면서, C++11 부터 대격변이 시작되는데... 여기서 많은 사람들이 좌측값과 우측값에 대한 개념을 헷갈려하기 시작한다(필자 포함). move semantics 가 뭔지 잘 모르겠다면, 이전 글(기초, 응용, 심화)을 꼭 읽고 오자..

C++ 에 대해 공부한 것과, 개발하면서 알게 된 것들을 다룹니다 const_cast 많은 사람들이 알고 있듯이, C++ 에서 제공하는 casting 의 종류는 크게 4 가지이다. 각 용도를 간단히 적어보면 다음과 같다 : static_cast : '일반적인' C 스타일의 캐스팅. 보통 업캐스팅(파생 클래스의 포인터를 기반 클래스의 포인터로 가리킴) 시 사용한다. dynamic_cast : 상속 관계에 있는 클래스들 사이의 캐스팅. 보통 다운 캐스팅(기반 클래스의 포인터를 파생 클래스의 포인터로 가리킴) 시 사용한다. 만약 실패하면 nullptr 를 리턴한다. 참고로, dynamic_cast 는 polymorphic 한 클래스만 가능한데, 간단히 말하면 virtual 함수가 포함된 클래스이어야 dynam..