C ++ 헤더의 "네임 스페이스 사용"


119

모든 C ++ 과정에서 모든 교사는 항상 파일 using namespace std;에서 #includes 바로 뒤에 배치 .h합니다. 그 이후로 다른 프로그램에 해당 헤더를 포함하면 내 프로그램으로 네임 스페이스를 가져올 수 있습니다. 그 이후로 이것은 나에게 위험한 것 같습니다. 아마도 그것을 깨닫거나 의도하거나 원하지 않는 것입니다 (헤더 포함은 매우 깊게 중첩 될 수 있습니다).

그래서 내 질문은 두 배입니다. using namespace헤더 파일에 사용해서는 안되는 것이 맞습니까? 그리고 / 또는 다음과 같은 실행 취소 방법이 있습니까?

//header.h
using namespace std {
.
.
.
}

같은 줄을 따라 한 가지 더 질문 : 헤더 파일에 #include해당 .cpp파일에 필요한 모든 헤더를 파일로 지정 하고 , 헤더 정의에 필요한 헤더 만 .cpp파일 #include에 나머지 파일로 두어야합니까 extern?
질문의 이유는 위와 동일 .h합니다. 파일을 포함 할 때 놀라움을 원하지 않습니다 .

또한 내가 옳다면 이것은 일반적인 실수입니까? 실제 프로그래밍과 "실제"프로젝트를 의미합니다.

감사합니다.



3
참고로, using namespace문 으로 인해 이름 충돌이 발생하면 정규화 된 이름을 사용하여 문제를 해결할 수 있습니다.
Marius Bancila

답변:


115

using namespace해당 헤더를 포함하는 다른 파일에서 코드의 의미를 예기치 않게 변경할 수 있다는 정확한 이유 때문에 헤더에 사용해서는 안됩니다 . using namespace너무 위험한 또 다른 이유 인 a를 실행 취소 할 방법이 없습니다 . 나는 일반적으로 더 복잡한 것을 시도하는 대신 헤더에서 호출되지 grep않도록하기 위해 또는 이와 유사한 것을 사용 using namespace합니다. 아마도 정적 코드 체커도 이것에 플래그를 지정합니다.

헤더에는 컴파일하는 데 필요한 헤더 만 포함되어야합니다. 이를 시행하는 쉬운 방법은 항상 다른 헤더보다 먼저 각 소스 파일의 자체 헤더를 먼저 포함하는 것입니다. 그러면 헤더가 자체 포함되지 않으면 소스 파일이 컴파일되지 않습니다. 예를 들어 라이브러리 내의 구현 세부 클래스를 참조하는 경우 #include와 같이 앞으로 선언 된 클래스의 정의를 완전히 제어 할 수 있기 때문에 대신 앞으로 선언을 사용할 수 있습니다 .

나는 그것을 일반적이라고 부를지 확신하지 못하지만, 때때로 부정적인 결과를 인식하지 못하는 새로운 프로그래머가 작성하는 경우가 있습니다. 일반적으로 위험에 대한 약간의 교육만으로도 비교적 쉽게 수정할 수 있으므로 모든 문제를 해결할 수 있습니다.


2
파일에 using진술을 자유롭게 사용할 .cpp수 있습니까? 3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator들 손가락에 죽음이다.
크리스토퍼

1
template헤더에 있어야 하는 함수를 어떻게 간소화해야 합니까? typedefs?
크리스토퍼

1
@donlan, 꽤 오랫동안 응답이없는 것 같습니다 ... 예, 범위가 해당 파일로 제한되기 때문에 파일 using내에서 명령문 을 사용할 수 .cpp있지만 #include명령문 전에는 절대 수행하지 않습니다 . 헤더에 정의 된 템플릿 함수에 관해서는, 불행히도 난 그냥 아마 당신은 넣을 수 ... 네임 스페이스를 작성하는 것보다 다른 좋은 솔루션의 모르는 using별도의 범위 내에서 선언 { /* using statement in between brackets */ }, 즉 적어도 현재 파일을 탈출을 방지 할 수 .
tjwrona1992 년

26

Sutter 및 Alexandrescu의 "C ++ 코딩 표준 : 101 규칙, 지침 및 모범 사례" 의 항목 59 :

59. 헤더 파일이나 #include 앞에 네임 스페이스 사용을 작성하지 마십시오.

네임 스페이스 using는 다른 사람에게 가하는 것이 아니라 사용자의 편의를위한 것 입니다. 지시문 앞에 using선언이나 using지시문을 작성하지 마십시오 #include.

결과 : 헤더 파일에서 네임 스페이스 수준 using지시문이나 using선언을 작성하지 마십시오 . 대신 모든 이름을 명시 적으로 네임 스페이스 한정합니다.

헤더 파일은 하나 이상의 소스 파일에있는 게스트입니다. using지시문과 선언 을 포함하는 헤더 파일 은 난폭 한 친구도 가져옵니다.

using 선언은 하나의 친구에 제공합니다. using 지침은 네임 스페이스의 모든 친구에 제공합니다. 선생님의 사용은 using namespace std;사용 지침입니다.

더 심각하게는 이름 충돌을 피하기위한 네임 스페이스가 있습니다. 헤더 파일은 인터페이스를 제공하기위한 것입니다. 대부분의 헤더는 현재 또는 미래에 어떤 코드에 포함될 수 있는지 알 수 없습니다. using헤더 내에 내부 편의를위한 명령문을 추가하면 해당 헤더의 모든 잠재적 클라이언트에 편리한 이름이 표시됩니다. 이름 충돌로 이어질 수 있습니다. 그리고 그것은 무례합니다.


12

헤더 내부에 헤더를 포함 할 때주의해야합니다. 대규모 프로젝트에서는 실제로 필요한 것보다 더 크고 긴 재 구축을 트리거하는 매우 복잡한 종속성 체인을 생성 할 수 있습니다. C ++ 프로젝트에서 좋은 물리적 구조의 중요성에 대해 자세히 알아 보려면 이 기사후속 기사를 확인하십시오 .

절대적으로 필요한 경우 (클래스의 전체 정의가 필요할 때마다) 헤더 안에 헤더를 포함하고 가능한 한 어디에서나 앞으로 선언을 사용해야합니다 (클래스가 필요한 경우 포인터 또는 참조).

네임 스페이스의 경우 헤더 파일에서 명시 적 네임 스페이스 범위를 사용하는 경향이 using namespace있으며 내 cpp 파일에만를 넣습니다 .


1
template함수 선언을 어떻게 간소화 합니까? 헤더에서 발생해야합니다.
크리스토퍼

6

Goddard Space Flight Center 코딩 표준 (C 및 C ++ 용)을 확인하십시오. 그것은 예전보다 조금 더 어려운 것으로 밝혀졌습니다-SO 질문에 대한 업데이트 된 답변을 참조하십시오.

GSFC C ++ 코딩 표준은 다음과 같이 말합니다.

§3.3.7 각 헤더 파일 #include은 사용자에게 #include필요한 파일 을 강요하지 않고 컴파일 하는 데 필요한 파일 이어야 합니다. #includes헤더에 필요한 것으로 제한됩니다. 다른 #includes것은 소스 파일에 있어야합니다.

상호 참조 된 질문 중 첫 번째 질문에는 이제 GSFC C 코딩 표준의 인용문과 근거가 포함되어 있지만 그 내용은 동일합니다.


5

using namespace헤더가 위험하다는 것이 맞습니다 . 나는 그것을 취소하는 방법을 모른다. 감지하기 쉽지만 using namespace헤더 파일에서 검색하기 만하면 됩니다. 마지막 이유 때문에 실제 프로젝트에서는 흔하지 않습니다. 경험이 많은 동료들은 누군가가 그런 일을하면 곧 불평 할 것입니다.

실제 프로젝트에서 사람들은 포함 된 파일의 양을 최소화하려고합니다. 포함하는 파일이 적을수록 컴파일 속도가 빨라지기 때문입니다. 그것은 모두의 시간을 절약합니다. 그러나 헤더 파일이 어떤 것이 먼저 포함되어야한다고 가정하는 경우에는 그 자체를 포함해야합니다. 그렇지 않으면 헤더가 자체 포함되지 않습니다.


4

당신이 옳습니다. 그리고 모든 파일에는 해당 파일에 필요한 헤더 만 포함되어야합니다. "실제 프로젝트에서 일반적으로 잘못된 일을하고 있습니까?" - 어 그래!


4

프로그래밍의 모든 것과 마찬가지로 실용주의가 독단주의, IMO를 이겨야합니다.

프로젝트 전체에서 결정을 내리는 한 ( "우리 프로젝트는 STL을 광범위하게 사용하며 모든 것을 std ::."앞에 추가 할 필요가 없습니다. ") 문제가 없다고 생각합니다. 당신이 위험에 처한 유일한 것은 이름 충돌이며 결국 STL의 편재성으로 인해 문제가 될 가능성은 거의 없습니다.

반면에 한 개발자가 단일 (비공개) 헤더 파일에서 결정을 내린 경우 팀간에 혼란을 야기하고 피해야하는 방법을 알 수 있습니다.


4

"[ using선언] 을 취소 할 수있는 방법이 있습니까?" 와 관련하여

using선언은 범위의 영향을 받는다는 점을 지적하는 것이 유용하다고 생각합니다 .

#include <vector>

{   // begin a new scope with {
    using namespace std;
    vector myVector;  // std::vector is used
}   // end the scope with }

vector myOtherVector;   // error vector undefined
std::vector mySTDVector // no error std::vector is fully qualified

그래서 효과적으로 그렇습니다. using선언 의 범위를 제한함으로써 그 효과는 해당 범위 내에서만 지속됩니다. 해당 범위가 끝나면 '취소'됩니다.

using선언이 다른 범위 밖의 파일에서 선언 되면 파일 범위가 있으며 해당 파일의 모든 것에 영향을줍니다.

헤더 파일의 경우 using선언이 파일 범위에 있으면 헤더가 포함 된 모든 파일의 범위로 확장됩니다.


2
당신은 실제 질문을 어떻게 이해했는지 유일한 사람인 것 같습니다 ... 그러나 내 컴파일은 클래스 감속 내부에서 사용하는 것에 대해별로 행복하지 않습니다.
rustypaper

이 답변은 범위가 어떻게 작동해야 하는가에 대한 OP의 아이디어 (예 : namespace 선언 ) 대 실제로 작동하는 방법 (변수와 같이)에 . {}포함하는 것은 그것 {}과 관련된 아무것도하지 않은 후에 그 범위를 제한 합니다. 그것은 using namespace전 세계적으로 적용되는 우연한 방법입니다 .
TafT

2

다음과 같이 중첩 된 네임 스페이스에 선언을 작성하면 C ++ 헤더에서 '사용'을 안전하게 사용할 수 있다고 생각합니다.

namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED
{
    /*using statements*/

    namespace DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED
    {
        /*declarations*/
    }
}

using namespace DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED::DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED;

여기에는 네임 스페이스를 사용하지 않고 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED'에 선언 된 항목 만 포함되어야합니다. mingw64 컴파일러에서 테스트했습니다.


이것은 내가 전에 보지 못했던 유용한 기술입니다. 감사. 일반적으로 나는 전체 범위 제한을 사용하고 가능한 한 using함수 정의 내부 에 선언을 넣어 함수 외부의 네임 스페이스를 오염시키지 않습니다. 하지만 이제 헤더 파일에서 C ++ 11 사용자 정의 리터럴을 사용하고 싶습니다. 일반적인 규칙에 따라 리터럴 연산자는 네임 스페이스로 보호됩니다. 하지만 비 오염 using선언을 사용할 수있는 범위에 있지 않은 생성자 이니셜 라이저 목록에서는 사용하고 싶지 않습니다 . 그래서 이것은 그 문제를 해결하는데 아주 좋습니다.
Anthony Hall

이 패턴의 불행한 부작용은 가장 안쪽 네임 스페이스 내에서 선언 된 모든 클래스가 정규화 된 이름으로 컴파일러 오류 메시지에 표시된다는 것 error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...입니다. 적어도 그것은 g ++에서 저에게 일어나는 일입니다.
Anthony Hall
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.