콘텐츠로 이동

스코프 (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 객체의 초기화와 소멸 순서를 설명할 수 있는가? 설명하기 어렵다면 대개 스코프가 너무 넓다는 신호입니다.
  • "일단 전역으로 두고 나중에 좁히자"는 판단을 하고 있지는 않은가? 넓힌 스코프는 사용자가 생기는 순간 되돌리기 어려워집니다.