[C/C++] const keyword
const
키워드를 적절히 사용할 수 있으면 유용하다. 코드 작성 중 발생할 수 있는 실수를 컴파일 단계에서 확인가능하기 때문에 활용하면 좋다.const
의 개념은 간단하다. 이 키워드를 통해 선언되면 프로그램 실행 중 변경할 수 없음을 지정한다. 이를 통해 할 수 있는 기능 중 하나는 상수 지정이다. 상수를 지정하는 다른 방법은 #define
을 이용하는 것이다. const
는 #define
보다 이점을 가지고 있다. 먼저 #define
을 사용할 경우는 단순 대체만 수행하기 때문에 타입 확인을 할 수 없는 반면 const
를 사용하면 컴파일러에서 확인이나 검사가 가능하다. 또한 const
변수를 이용하면 디버거에서 변수를 이용할 수 있어 디버깅에 유용하다.
포인터와 const
가 결합되면 확인이 다소 어렵다.
int* p1;
const int* p2;
int* const p3;
const int* const p4;
p2와 p3의 경우 const
키워드에 영향을 받는 것이 어느 부분인지 헷갈린다.
(const int*) p2;
int* (const p3);
cosnt
는 바로 오른쪽의 내용을 제한한다고 보면 된다. p2는 p2의 값은 바꿀 수 있지만 p2가 가리키는 값은 변경하지 못한다. p3는 p3의 값을 바꿀 수 없지만 p3가 가리키는 값은 바꿀 수 있다.
p2 = #
*p2 = 1; //compile error
p3 = # //compile error
*p3 = 1;
const
의 또 다른 활용은 함수 인자와 반환 값에 적용하는 것이다. 함수 호출 시 인자에 매우 큰 값이 올경우 복사가 일어나면 비효율적일 것이다. 이 때 참조나 포인터형을 받으면 복사에 필요한 비용이 줄지만 인자의 변경 가능성이 생긴다. const
는 이 가능성을 제한해준다. const
를 통해 인자의 포인터가 성능상의 이유로 쓰인건지, 값을 변경하려는지 의도를 파악할 수 있다. 또한 함수 작성 중 실수로 인자 변경이 일어날 경우 컴파일 단계에서 제한해준다.
리턴값에도 const
를 지정해 줄 수 있다.
class Player{
private:
char name[32];
pulbic:
void SetName(char* name);
char* GetName() {
return name;
}
}
GetName 호출을 통해 Player.name을 가리키는 배열을 받게 된다. Player 클래스의 의도는 SetName() 호출을 통해서만 name을 수정할 수 있다. 하지만 GetName()의 반환값이 char*이기 때문에 포인터 접근을 통한 값의 변경이 일어날 수 있다. 이런 경우를 방지하고자 return값에 const
를 붙여준다.
C++에서는 const
의 의미를 확장하여 클래스 멤버 함수들에 이용할 수 있도록 하였다.
class Player{
private:
char name[32];
pulbic:
void SetName(char* name);
const char* GetName() const {
return name;
}
}
GetName() 멤버함수 인자 괄호 뒤에 const
가 추가 되었다. 이것은 해당 멤버함수가 멤버 변수를 변경하지 않음을 지정해 준다. 만일 멤버변수를 변경하는 시도를 하면 컴파일 오류를 낸다.
const
를 제대로 활용하기 위해서는 적용해야할 모든 곳에 const
를 적용해야 한다. 코딩을 하며 실수를 많이 하는 입장에서 이런 실수를 줄여줄 수 있는 방법을 잘 사용해야겠다.