코딩 / 프로젝트 표준?
쉽게 말하면 코딩 스타일
구글 코딩 표준
https://google.github.io/styleguide/cppguide.html
언리얼 코딩 표준
표준을 왜 따라야하지?
작성된 코드는 한 사람이 만든 것 처럼 통일된 방식으로 작성되어야 코드를 분석하는 시간을 줄여 프로젝트 효율을 높임
소프트웨어 총 수명 비용중 80%가 유지 보수에 사용된다 함
읽는 사람을 염두로
퍼블릭 인터페이스에서 먼저 선언 후 클래스의 프라이빗 구현
class HELLOU_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public: // 퍼블릭 먼저
private: // 그 다음 프라이빗
};
단순히 카피라이트 주석같은거 지우지 말라는거
파스칼 케이싱: 합성어 첫 글자를 대문자로
카멜 케이싱: 첫 합성어는 소문자, 나머지는 대문자
스네이크 케이싱: 합성어 사이에 언더바
언리얼에서는 파이스칼 케이싱 사용해야 함
UObject 에서 상속받는 클래스에는 접두사 U 포함AActor 에서 상속받는 클래스에는 접두사 A 포함SWidget 에서 상속받는 클래스에는 접두사 S 포함더 자세한건 위에 언리얼 문서 링크로
IsVisible() 또는 ShouldClearBuffer() 등의 true/false 질문으로bool - 부울 값(부울 크기 추정 금지). BOOL 은 컴파일되지 않음TCHAR - character(문자) (TCHAR 크기 추정 금지)uint8 - unsigned byte(부호 없는 바이트) (1바이트)int8 - signed byte(부호 있는 바이트) (1바이트)uint16 - unsigned 'shorts'(부호 없는 'short') (2바이트)int16 - signed 'short'(부호 있는 'short')(2바이트)uint32 - unsigned int(부호 없는 int) (4바이트)int32 - signed int(부호 있는 int) (4바이트)uint64 - unsigned 'quad word'(부호 없는 '쿼드 단어') (8바이트)int64 - signed 'quad word'(부호 있는 '쿼드 단어') (8바이트)float - 단정밀도 부동 소수점(4바이트)double - 배정밀도 부동 소수점(8바이트)PTRINT - 포인터를 가질 수 있는 정수(PTRINT 크기 추정 금지)게임엔진은 메모리를 효율적으로 사용해야하기 때문(메모리 크기파악이 중요)
너무 범용적이니 알맞지 않다.
언리얼꺼 쓰라는 뜻
cosnt 쓸수 있는 변수면 const쓰는게 좋다.
그래야 협업할 때 아 이건 변경하면 안되는 인자구나 인지할 수 있음
루프문에서 값이 변경되면 루프 데이터가 깨질수 있으니 루프문에서는 엘리먼트에 const로 지정해주는게 좋다.(물론 예외사항도 있다. 보통 이 경우 주석을 단다.)
void SomeMutatingOperation(FThing& OutResult, const TArray<Int32>& InArray)
{
// InArray는 여기서 수정되지 않지만, OutResult는 수정될 수도 있습니다.
}
void FThing::SomeNonMutatingOperation() const
{
// 이 코드는 자신을 호출한 FThing을 수정하지 않습니다.
}
TArray<FString> StringArray;
for (const FString& : StringArray)
{
// 이 루프의 바디는 StringArray를 수정하지 않습니다.
}
포인터에 증감연산자 사용금지 할때 cosnt 를 쓸 수도 있음
포인터가 가르키는 데이터는 const 가 아니기 때문에 변경 가능
// const 포인터에서 const 이외 오브젝트 - 포인터로의 재할당은 불가하나, T는 여전히 수정 가능합니다.
T* const Ptr = ...;
// 틀림
T& const Ref = ...;
레퍼런스 자체가 수정 불가기 때문에 레퍼런스에는 const 안쓴다.
C스타일 NULL대신 C++의 nullptr을 써서 널 체크 해야함
몇 가지 예외를 제외하면 auto키워드 사용하지 마라
이터레이터: 컨테이너(배열, 리스트, 맵 등)의 요소를 순회(Iterate)하는 객체 또는 포인터
TArray<int32> Numbers = {1, 2, 3, 4, 5};
// auto 사용 전
for (TArray<int32>::TIterator It = Numbers.CreateIterator(); It; ++It) {
UE_LOG(LogTemp, Log, TEXT("%d"), *It);
}
// auto 사용 후
for (auto It = Numbers.CreateIterator(); It; ++It) {
UE_LOG(LogTemp, Log, TEXT("%d"), *It);
}
TMap<FString, int32> MyMap;
// 기존 스타일
for (auto It = MyMap.CreateIterator(); It; ++It)
{
UE_LOG(LogCategory, Log, TEXT("Key: %s, Value: %d"), It.Key(), *It.Value());
}
// 새 스타일
for (TPair<FString, int32>& Kvp : MyMap)
{
UE_LOG(LogCategory, Log, TEXT("Key: %s, Value: %d"), *Kvp.Key, Kvp.Value);
}
Enum 클래스는 항상 일반 열거형이든 UENUM 이든 기존 네임스페이스 열거형을 대체하여 사용
// 기존 열거형
UENUM()
namespace EThing
{
enum Type
{
Thing1,
Thing2
};
}
// 새 열거형
UENUM()
enum class EThing : uint8
{
Thing1,
Thing2
}
포인터 선언시 아래처럼
FShaderType* Ptr
나쁜 예
FShaderType *Ptr
FShaderType * Ptr
// SomeModule.h
static const FString GUsefulNamedString = TEXT("String");Copy full snippet
이러한 코드는 다음으로 대체해야 함
// SomeModule.h
extern SOMEMODULE_API const FString GUsefulNamedString;
// SomeModule.cpp
const FString GUsefulNamedString = TEXT("String");Copy full snippet