본문 바로가기

Programming/CPP

[CPP] 함수 반환형이 갖는 의미

여러 프레임워크를 사용하다 보면,

어떤 함수는 반환형이 있고 어떤 함수는 반환형이 없는 대신 참조에 의한 결과값 전달을 수행한다.

 

왜 이런 차이가 있을까? 여기에는 어떤 의미가 있는걸까?


예를 들어 이런 함수 시그니처가 있다고 가정해 보자.

 

멤버 변수를 보면, OutExecutionOutput 이라는 참조 변수를 통해 결과값을 전달한다는 것을 알 수 있다.

 

const 가 없고, 참조가 있는 이유는 바로 결과값 전달을 위해선 비 const 여야 하고, 참조로 받아야 결과를 받을 수 있기 때문이다.

 

그런데 왜 직접 FGameplayEffectCustomExecutionOutput& 으로 반환하면 안되는걸까?


 

자, 우선 반환형을 FGameplayEffectCustomExecutionOutput& 로 하기 위해서는 해당 함수 내부에서 FGameplayEffectCustomExecutionOutput 를 생성해야 하는데, 해당 함수의 블록이 종료되는 순간 지역변수는 스택에서 사라지게 된다. 그러므로 static 멤버, 혹은 함수의 바깥에서 주소나 참조를 통해 건네받지 않는 이상 위와 같은 반환은 불가능하다.

 

더구나, 함수 내에서 새로 할당을 한다고 하더라도 만약 이게 굉장히 큰 구조체인 경우 여기서 상당한 비용이 발생한다. 함수라는 것은 계속해서 불리기 위한 도구이기 때문에 최악의 경우를 가정했을 때 크기가 10KB인 구조체를 1000번 만들고 지우고 해야 할 수 있다.

 

전자의 경우, 바깥에서 건네받으면 결국 FGameplayEffectCustomExecutionOutput& Function( FGameplayEffectCustomExecutionOutput& Execution) 으로 쓸데없이 동일한 참조형을 사용해서 함수를 만들 이유가 전혀 없어 보인다.

 

후자의 경우에도 이를 함수 내에서 수행하는 것 보다는 바깥에서 수행하는 것이 종합적인 메모리 관리에 도움이 된다.

 

그렇기 때문에 위와 같은 시그니처를 사용하여 결과 값을 반환하여 메모리 관리에 중점을 둘 수 있게 된다.


 

이 외에는, 예를 들어 결과값 여러 개를 반환해야 하는 경우나 그냥 정말 데이터가 너무 커서 주소로 관리해야 할 경우에도 이런 시그니처를 사용할 것이다.

 

그렇지 않은 경우.

예를 들어 이미 존재하는 포인터를 반환하거나

동적으로 오브젝트를 생성하는 함수라서 필요한 경우 (이미 Heap 영역에 들어가, 이를 참조하는 주소를 반환해야 하거나)

아니면 static 멤버에 대한 주소를 반환하는 경우에는

함수가 FGameplayEffectCustomExecutionOutput&  혹은 FGameplayEffectCustomExecutionOutput* 라는 반환형을 사용할 수도 있을 것이다.

 

 

이런 부분들을 알고 코드를 보는 것과 모르고 보는 것은 차이가 있다.

제대로 이해하고 본다면, 이런 시그니처만 봐도 어떤 작업을 수행할지 눈에 보이고 작성한 사람이 어떤 의도로 이런 코드를 작성했는지도 파악할 수 있다.

 

필자는 이런 당연한(?) 부분들을 정리하는 것을 좋아해서 앞으로 블로그에 생각나는대로 적어놓으려고 한다.

'Programming > CPP' 카테고리의 다른 글

[CPP] Visual Studio 사용 시 불편한 점 해결  (0) 2024.08.04