한글 번역
Tip of the Week #109: 함수 선언에서 의미 있는 const 사용
Greg Miller (jgm@google.com)
2016-01-14에 totw/109로 최초 게시
이 문서는 함수 선언에서 const가 언제 의미가 있고, 언제 의미가 없어 생략하는 것이 최선인지 설명합니다. 먼저, *선언(declaration)*과 *정의(definition)*의 차이를 간단히 살펴보겠습니다.
다음 코드를 봅시다:
void F(int); // 1: F(int)의 선언
void F(const int); // 2: F(int)의 재선언
void F(int) { /* ... */ } // 3: F(int)의 정의
void F(const int) { /* ... */ } // 4: 오류: F(int)의 재정의
1번과 2번은 함수 선언입니다. 함수 선언은 함수의 시그니처(signature)와 반환 타입을 컴파일러에 알려줍니다. 위 예제에서 함수의 시그니처는 F(int)입니다. 함수 매개변수 타입의 const 여부는 무시되므로 두 선언은 동일합니다. (참조: “Overloadable declarations”
)
3번과 4번은 함수 정의입니다. 함수 정의는 함수의 본문도 포함하기 때문에 선언의 역할도 합니다. 따라서 3번은 F(int) 시그니처를 가진 함수의 정의입니다. 마찬가지로 4번도 동일한 함수의 정의이므로 링크 단계에서 오류가 발생합니다. 여러 번 선언은 가능하지만 정의는 한 번만 허용됩니다.
3번과 4번의 정의는 같은 함수를 선언하고 정의하지만, 선언 방식에 따라 함수 본문 내에서 차이가 있습니다. 3번 정의에서 함수 매개변수는 int(비-const) 타입이고, 4번 정의에서는 매개변수가 const int 타입입니다.
함수 선언에서 의미 있는 const
모든 const가 함수 선언에서 무시되는 것은 아닙니다. C++ 표준의 “Overloadable declarations”([over.load])에는 다음과 같이 나와 있습니다(강조 추가):
“매개변수 타입 명세 내에 포함된
const타입 지정자는 중요하며, 오버로드된 함수 선언을 구분하는 데 사용할 수 있습니다.”
다음은 const가 중요하며 무시되지 않는 예제입니다:
void F(const int* x); // 1
void F(const int& x); // 2
void F(std::unique_ptr<const int> x); // 3
void F(int* x); // 4
위 예제에서 매개변수 x 자체가 const로 선언된 것은 아닙니다. 각 함수는 x의 서로 다른 타입을 받아 유효한 오버로드 집합을 형성합니다.
- 1번은 “포인터가 가리키는 값이
const int인 함수"를 선언합니다. - 2번은 “
const int에 대한 참조를 매개변수로 받는 함수"입니다. - 3번은 “
const int를 가리키는unique_ptr을 매개변수로 받는 함수"입니다.
이러한 경우 const는 타입 명세의 일부로 간주되며, 매개변수 x 자체의 최상위(top-level) const 여부와는 다릅니다.
다음은 const가 의미 없고 무시되는 예제입니다:
void F(const int x); // 1: F(int) 선언
void F(int* const x); // 2: F(int*) 선언
void F(const int* const x); // 3: F(const int*) 선언
간단한 규칙
C++의 복잡한 규칙을 완벽히 숙지하기는 어렵지만, 가능한 한 규칙을 이해하여 다른 C++ 프로그래머와 협업할 수 있는 코드를 작성하는 것이 중요합니다. 이를 위해 함수 선언에서 const의 의미와 무시되는 경우를 알아야 합니다.
아래는 하나의 합리적인 지침입니다:
정의가 아닌 함수 선언에서는 최상위
const를 사용하지 마세요.- 컴파일러에 의해 무시되며, 불필요한 시각적 잡음이 될 수 있고, 독자를 혼란스럽게 만들 수 있습니다.
- 특히 무의미한
const를 복사/붙여넣기하지 않도록 주의하세요.
함수 정의에서는 최상위
const를 선택적으로 사용하세요.- 함수 내 로컬 변수를
const로 선언할 때와 동일한 기준을 적용할 수 있습니다.
- 함수 내 로컬 변수를
댓글