const 사용 (Use of const)¶
API에서는 의미가 통하는 곳마다 const를 사용하세요. const의 일부 용도에는 constexpr이 더 나은 선택입니다.
정의:
선언하는 변수와 매개변수 앞에 const 키워드를 붙여 그 변수가 바뀌지 않음을 나타낼 수 있습니다(예: const int foo). 클래스의 함수에는 const 한정자를 붙여 그 함수가 클래스 멤버 변수의 상태를 바꾸지 않음을 나타낼 수 있습니다(예: class Foo { int Bar(char c) const; };).
장점:
변수가 어떻게 쓰이는지 사람들이 이해하기 쉬워집니다. 컴파일러가 더 나은 타입 검사를 할 수 있고, 어쩌면 더 나은 코드를 생성할 수도 있습니다. 자신이 호출하는 함수가 변수를 바꿀 수 있는 범위가 제한되어 있음을 알기 때문에, 프로그램이 올바르다는 확신을 갖는 데 도움이 됩니다. 다중 스레드 프로그램에서 어떤 함수를 락 없이 써도 안전한지 아는 데에도 도움이 됩니다.
단점:
const는 전염성이 있습니다. const 변수를 함수에 넘기면 그 함수의 원형에도 const가 있어야 합니다(없으면 변수에 const_cast가 필요해집니다). 라이브러리 함수를 호출할 때 특히 문제가 될 수 있습니다.
결정:
의미가 통하고 정확한 곳이라면 API에서(즉 함수 매개변수, 메서드, 비지역 변수에서) const를 쓰기를 강력히 권장합니다. 이렇게 하면 어떤 연산이 어떤 객체를 변경할 수 있는지에 대한, 대체로 컴파일러가 검증해 주는 일관된 문서가 만들어집니다. 읽기와 쓰기를 구별하는 일관되고 믿을 만한 방법을 갖추는 것은 스레드 안전한 코드를 작성하는 데 결정적이며, 그 밖의 여러 맥락에서도 유용합니다. 특히 다음과 같습니다.
- 함수가 참조나 포인터로 전달받은 인수를 수정하지 않겠다고 보장한다면, 그에 대응하는 함수 매개변수는 각각 const에 대한 참조(
const T&)나 const에 대한 포인터(const T*)여야 합니다. - 값으로 전달되는 함수 매개변수에서는
const가 호출자에게 아무런 영향을 주지 않으므로, 함수 선언에서는 권장하지 않습니다. TotW #109를 참조하세요. - 메서드는
const로 선언하세요. 다만 그 메서드가 객체의 논리적 상태를 바꾸거나(또는 사용자가 그 상태를 바꿀 수 있게 하거나. 예를 들어 const가 아닌 참조를 반환하는 경우인데, 이는 드뭅니다), 동시에 호출해도 안전하지 않은 경우는 예외입니다.
지역 변수에 const를 쓰는 것은 권장하지도, 말리지도 않습니다.
클래스의 모든 const 연산은 서로 동시에 호출해도 안전해야 합니다. 그것이 불가능하다면 그 클래스는 "스레드 안전하지 않음"이라고 분명히 문서화해야 합니다.
const를 어디에 둘 것인가¶
어떤 사람들은 const int* foo보다 int const* foo 형태를 선호합니다. 이쪽이 더 일관적이어서 더 읽기 좋다는 것인데, const가 언제나 자신이 수식하는 대상 뒤에 온다는 규칙을 지키기 때문이라는 주장입니다. 하지만 이 일관성 논거는 깊게 중첩된 포인터 표현식이 별로 없는 코드베이스에는 해당되지 않습니다. 대부분의 const 표현식에는 const가 하나뿐이고 그것이 밑바탕 값에 적용되기 때문입니다. 그런 경우에는 유지할 일관성이라는 것이 애초에 없습니다. const를 앞에 두는 편이 오히려 더 읽기 좋다고 볼 수 있는데, "형용사"(const)를 "명사"(int) 앞에 두는 영어의 어순을 따르기 때문입니다.
그렇다고는 해도, const를 앞에 두기를 권장하기는 하지만 강제하지는 않습니다. 다만 주변 코드와는 일관되게 하세요!
옮긴이 풀이¶
핵심: 의미가 있으면 API에 const를 붙여라¶
함수 매개변수, 메서드, 비지역 변수 등 API에서 의미가 맞으면 const를 쓰세요. 무엇이 바뀌고 무엇이 안 바뀌는지를 컴파일러가 검증하는 문서로 남기는 셈이며, 스레드 안전성 추론에도 중요합니다.
어디에 붙이나¶
- 참조·포인터로 받은 인자를 수정하지 않으면 →
const T&,const T* - 값으로 받는 매개변수의
const는 호출자에게 영향이 없으므로 선언부에 쓰지 않는 게 권장됩니다. - 객체의 논리적 상태를 바꾸지 않는 메서드 →
const메서드. 클래스의 모든const연산은 서로 동시 호출에 안전해야 합니다(아니면 "스레드 안전하지 않음"을 명확히 문서화). - 지역 변수의
const는 권장도 비권장도 아닙니다(자유).
참고¶
- 진짜 상수라면
constexpr이 더 맞는 경우가 많습니다. const는 전염성이 있습니다 —const값을 넘기면 받는 함수의 시그니처도const여야 합니다(아니면const_cast가 필요).- 위치는
const int* p(const 먼저)를 권장하지만 필수는 아닙니다. 주변 코드와 일관되게 하세요.