주간 팁 #130: 네임스페이스 이름 지정
원래 게시일: 2017-02-17
작성자: Titus Winters (titus@google.com)
정확한 이름 지정은 보는 이의 독창성을 제한한다.
— 피에르 보나르(Pierre Bonnard)
Google C++ 스타일 가이드 초기에는 네임스페이스 이름 지정에 대한 지침이 포함되어 있었습니다. 이 지침은 일반적으로 다음과 같이 요약될 수 있습니다:
네임스페이스는 패키지 경로에서 파생됩니다.
이는 Java 패키지 이름 지정 요구사항의 영향을 받아 합리적으로 보였습니다. C++에서 고유한 심볼을 식별하고 네임스페이스 선택에서 일관성을 유지하기 위해 도입된 것입니다.
그러나 시간이 지나면서 이 방식이 C++에서는 문제가 있다는 것을 깨닫게 되었습니다.
이름 검색(Name Lookup)
C++의 이름 검색 방식과 Java와의 차이점을 살펴보겠습니다.
C++의 이름 검색:
namespace foo {
namespace bar {
void f() {
Baz b;
}
}
}
- C++에서는 미수식 이름(
Baz
)에 대한 검색이 확장된 범위에서 수행됩니다:f()
함수 내부bar
네임스페이스foo
네임스페이스- 전역 네임스페이스
Java의 이름 검색:
public void f() {
com.google.foo.bar.Baz b = new com.google.foo.bar.Baz();
}
- Java에서는 미수식 이름이 없습니다. 모든 이름은:
- 명시적으로 수식된 이름(예:
com.google.foo.bar.Baz
)이거나, import
를 통해 가져옵니다.
- 명시적으로 수식된 이름(예:
Java에서는 부모 패키지나 하위 패키지를 자동으로 검색하지 않습니다. 이는 Java와 C++의 네임스페이스 설계에서 본질적인 차이를 만듭니다.
문제점
1. 깊은 네임스페이스 중첩의 문제
C++에서는 미수식 이름을 사용하는 경우가 많습니다(std::unique_ptr
대신 unique_ptr
).
하지만 깊게 중첩된 네임스페이스에서는 이름 충돌이 발생할 가능성이 커집니다.
예를 들어, std::unique_ptr
을 사용할 때 다음 네임스페이스들 중 어느 것이 참조되는지 예측할 수 없습니다:
::std::unique_ptr
::division::std::unique_ptr
::division::section::std::unique_ptr
::division::section::team::std::unique_ptr
2. 잘못된 심볼 참조
검색이 하위 네임스페이스에서 시작하여 일치하는 첫 번째 심볼에서 멈추므로, 예기치 않은 심볼이 참조될 수 있습니다.
이로 인해 컴파일 오류가 발생하거나 런타임에서 호환되지 않는 API가 호출되어 오류가 발생할 수 있습니다.
해결 방안
이 문제를 해결하려면 두 가지 원칙을 따르는 것이 중요합니다:
- 최상위 네임스페이스의 이름 충돌 방지:
- 하위 네임스페이스가 상위 네임스페이스 이름과 충돌하지 않도록 합니다.
- 미수식 이름 사용 최소화:
- 네임스페이스 밖의 이름은 항상 완전히 수식합니다.
3가지 접근법
- 모든 이름을 완전히 수식:
::std::unique_ptr
처럼 항상 네임스페이스를 완전히 명시.- 이는 안전하지만 매우 장황하여 비현실적입니다.
- 네임스페이스 중복을 자동으로 탐지하는 도구 개발:
- 새 네임스페이스 추가 시 기존 네임스페이스와의 충돌 여부를 검사.
- 최상위 네임스페이스를 단일화:
- 각 프로젝트별로 단일 최상위 네임스페이스를 사용(예:
absl
). - 이 접근법은 충돌 가능성을 줄이고, 이름 지정의 간결성을 유지.
- 각 프로젝트별로 단일 최상위 네임스페이스를 사용(예:
Google 스타일 가이드는 세 번째 방식을 권장합니다.
“작은 네임스페이스가 더 조직적이다”는 오해
작은 네임스페이스가 코드 구조를 더 체계적으로 만든다는 의견이 있습니다.
그러나 C++에서는 부모 네임스페이스에서의 이름 충돌 가능성이 작을수록 안전합니다.
즉, 네임스페이스를 세분화한다고 해서 안전해지는 것이 아니라, 오히려 충돌 가능성이 증가할 수 있습니다.
베스트 프랙티스
- 네임스페이스 고유성 관리:
- 코드베이스에 등록된 네임스페이스 데이터베이스를 사용해 고유성을 확인.
- 최상위 네임스페이스 사용:
- 각 프로젝트는 하나의 최상위 네임스페이스를 사용.
- 네임스페이스 별칭 사용 시 완전 수식:
- TotW 119를 참고.
결론
깊게 중첩된 네임스페이스 사용은 C++에서 이름 충돌과 유지보수성을 저하시킬 수 있습니다.
최상위 네임스페이스를 통일하고, 필요한 경우 완전 수식을 사용하여 충돌을 방지하는 것이 가장 좋은 접근법입니다.