title: “주간 팁 #153: using-directives
를 사용하지 마세요”
layout: tips
sidenav: side-nav-tips.html
published: true
permalink: tips/153
type: markdown
order: “153”
—
원래 2018년 7월 17일에 TotW #153으로 게시됨
작성자: Roman Perepelitsa와 Ashley Hedberg
2020-04-06 업데이트
빠른 링크: abseil.io/tips/153
“나는 using-directives
를 시한폭탄으로 봅니다. 이를 사용하는 사람이나 언어 시스템 모두에게 위험합니다.”
– Ashley Hedberg, 워렌 버핏을 빌려서
요약
using-directives
(using namespace foo
)는 Google 스타일 가이드에서 금지될 만큼 위험합니다. 향후 업그레이드가 필요한 코드에서는 이를 사용하지 마세요.
이름을 짧게 줄이고 싶다면, 대신 네임스페이스 별칭 (namespace baz = ::foo::bar::baz;
)이나 using-선언 (using ::foo::SomeName
)을 사용하세요. 스타일 가이드에서는 특정 문맥(예: *.cc
파일)에서 이를 허용합니다.
함수 범위에서의 using-directives
다음 코드는 무엇을 할까요?
namespace totw {
namespace example {
namespace {
TEST(MyTest, UsesUsingDirectives) {
using namespace ::testing;
Sequence seq; // ::testing::Sequence
WallTimer timer; // ::WallTimer
...
}
} // namespace
} // namespace example
} // namespace totw
대다수의 C++ 사용자들은 using-directive
가 선언된 범위(이 경우 함수 범위)에 이름을 주입한다고 생각합니다. 하지만 실제로는 대상 네임스페이스(::testing
)와 사용 네임스페이스(::totw::example::anonymous
)의 가장 가까운 공통 조상 네임스페이스에 이름을 주입합니다. 위 예제에서는 전역 네임스페이스입니다!
결과적으로 코드는 다음과 비슷합니다:
using ::testing::Expectation;
using ::testing::Sequence;
using ::testing::UnorderedElementsAre;
...
namespace totw {
namespace example {
namespace {
TEST(MyTest, UsesUsingDirectives) {
Sequence seq; // ::testing::Sequence
WallTimer timer; // ::WallTimer
...
}
} // namespace
} // namespace example
} // namespace totw
이 변환은 정확히 동일하지는 않습니다. 이름이 실제로 함수 범위 외부에서 계속 보이지는 않지만, 전역 범위에 임시로 주입되는 것만으로도 문제가 생길 수 있습니다.
어떤 변화가 이 코드를 깨뜨릴 수 있을까요?
::totw::Sequence
나::totw::example::Sequence
가 정의되면,seq
는 더 이상::testing::Sequence
를 참조하지 않을 수 있습니다.::Sequence
가 정의되면,seq
정의가 컴파일되지 않을 수 있습니다.Sequence
가::testing::Sequence
인지::Sequence
인지 컴파일러가 모호해할 것입니다.::testing::WallTimer
가 정의되면,timer
정의가 컴파일되지 않을 수 있습니다.
따라서 함수 범위에서의 단일 using-directive
가 ::testing
, ::totw
, ::totw::example
, 전역 네임스페이스에 이름 충돌 위험을 만듭니다.
무자격 using-directives
함수 내에서 하나의 using-directive
로 문제가 생긴다면, 여러 개의 무자격 using-directive
를 사용하면 어떨까요?
namespace totw {
namespace example {
namespace {
using namespace rpc;
using namespace testing;
TEST(MyTest, UsesUsingDirectives) {
Sequence seq; // ::testing::Sequence
WallTimer timer; // ::WallTimer
RPC rpc; // ...이건 ::rpc::RPC인가, ::RPC인가?
...
}
} // namespace
} // namespace example
} // namespace totw
무슨 일이 발생할 수 있을까요? 생각보다 많은 일이 생길 수 있습니다:
- 함수 수준 예제에서의 모든 문제가 여전히 발생하며,
::testing
과::rpc
각각에 대해 두 배로 문제가 생깁니다. ::rpc
와::testing
네임스페이스가 동일한 이름의 심볼을 선언하면, 이 코드는 컴파일되지 않을 수 있습니다.::rpc::testing
과 같은 하위 네임스페이스가 도입되면 이 코드는 컴파일되지 않을 가능성이 있습니다.
이 기능은 왜 존재할까요?
using-directives
는 제네릭 라이브러리 내에서 드물게 합법적으로 사용될 수 있지만, 매우 희소한 경우라 여기나 스타일 가이드에서 다룰 필요조차 없습니다.
결론
using-directives
는 시한폭탄입니다. 오늘 컴파일되던 코드가 언어 버전 변경이나 심볼 추가로 인해 쉽게 컴파일되지 않을 수 있습니다. 외부 코드가 단명하고 종속성이 변경되지 않는다면 이는 감수할 수 있는 위험일 수 있습니다. 그러나 장기적으로 유지보수가 필요한 프로젝트에서는 이 시한폭탄이 언젠가 터질 가능성이 큽니다.