스코프 (Scoping)¶
원문에 대한 안내
원문의 Scoping 절에는 별도의 본문 설명 없이 하위 항목만 있습니다. 따라서 이 페이지에는 번역할 원문 본문이 없으며, 아래 옮긴이 풀이는 옮긴이가 덧붙인 부가 설명입니다.
이 절은 다음 하위 항목으로 구성됩니다.
옮긴이 풀이¶
스코프란?¶
스코프(scope)는 어떤 이름이 "보이는" 소스 코드상의 구간입니다. C++에는 대략 다음과 같은 스코프가 있습니다.
int g; // 전역(네임스페이스) 스코프 -- 프로그램 전체에서 보임
namespace proj {
int n; // 네임스페이스 스코프 -- proj:: 로 접근
}
namespace {
int anon; // 이름 없는 네임스페이스 -- 이 .cc 파일 안에서만 보임
}
class C {
int m_; // 클래스 스코프 -- 멤버로만 접근
};
void f() {
int local; // 함수(블록) 스코프 -- f 안에서만 보임
{
int inner; // 더 좁은 블록 스코프
}
}
여기서 함께 따라오는 개념이 수명(lifetime)과 연결(linkage)입니다. 스코프가 "어디서 이름이 보이는가"라면, 수명은 "언제부터 언제까지 객체가 살아 있는가", 연결은 "다른 번역 단위(다른 .cc 파일)에서 같은 이름을 참조할 수 있는가"를 뜻합니다. 이 절의 규칙들은 이 세 가지를 함께 좁히는 방향을 이야기합니다.
이 절을 관통하는 원칙: 가능한 한 좁게¶
스코프 규칙의 핵심 질문은 하나입니다.
"이 이름이 정말 이만큼 넓은 범위까지 보여야 하는가?"
범위를 좁힐수록 다음이 함께 줄어듭니다.
- 이름 충돌 — 보이는 범위가 좁으면 부딪힐 상대도 적습니다.
- 읽는 사람이 추적할 대상 — 어떤 변수가 파일 안에서만 쓰인다는 사실이 보장되면, 그 파일만 읽고도 동작을 이해할 수 있습니다.
- 의도치 않은 결합 — 밖에서 참조할 수 없는 구현은 자유롭게 바꾸거나 지울 수 있습니다.
- 초기화·소멸 순서 문제 — 전역/정적 객체가 줄어들면 순서에 의존하는 버그도 줄어듭니다.
하위 항목이 다루는 것¶
| 하위 항목 | 다루는 범위 | 한 줄 요약 |
|---|---|---|
| 네임스페이스 | 전역 스코프의 분할 | 코드는 프로젝트 고유 네임스페이스 안에 두고, using namespace는 쓰지 않습니다. |
| 내부 연결 | 번역 단위 경계 | .cc 안에서만 쓰는 것은 이름 없는 네임스페이스나 static으로 숨깁니다. |
| 비멤버·정적 멤버·전역 함수 | 함수의 소속 | 상태가 필요 없는 함수는 클래스의 정적 멤버보다 네임스페이스 안의 비멤버 함수로 둡니다. |
| 지역 변수 | 함수 안 | 가능한 한 좁은 스코프에서, 처음 쓰는 지점 가까이에 선언과 동시에 초기화합니다. |
| 정적 및 전역 변수 | 프로그램 수명 | 정적 수명을 갖는 객체는 소멸자 순서 문제 때문에 강하게 제한됩니다. |
thread_local 변수 |
스레드 수명 | 편리하지만 비용과 초기화 규칙이 있어 조건부로만 허용됩니다. |
실무 점검 목록¶
- 파일 안에서만 쓰는 도우미 함수·상수를 헤더에 노출하고 있지는 않은가? (→ 이름 없는 네임스페이스로)
- 헤더에서
using선언이나 네임스페이스 별칭으로 남의 이름을 끌어와, 그 헤더를 포함하는 모든 파일에 흘리고 있지는 않은가? - 지역 변수를 함수 맨 위에 몰아 선언해 두고 한참 뒤에 쓰고 있지는 않은가?
- 전역·정적·
thread_local객체의 초기화와 소멸 순서를 설명할 수 있는가? 설명하기 어렵다면 대개 스코프가 너무 넓다는 신호입니다. - "일단 전역으로 두고 나중에 좁히자"는 판단을 하고 있지는 않은가? 넓힌 스코프는 사용자가 생기는 순간 되돌리기 어려워집니다.