c++ - 이름없는 네임 스페이스가 사용되는 이유와 그 이점은 무엇입니까?


방금 C + + 소프트웨어 프로젝트에 합류하여 디자인을 이해하려고합니다. 이 프로젝트는 이름없는 네임 스페이스를 자주 사용합니다. 예를 들어, 다음과 같은 내용이 클래스 정의 파일에서 발생할 수 있습니다.

// newusertype.cc
namespace {
  const int SIZE_OF_ARRAY_X;
  const int SIZE_OF_ARRAY_Y;
  bool getState(userType*,otherUserType*);
}

newusertype::newusertype(...) {...

이름없는 네임 스페이스를 사용하게하는 디자인 고려 사항은 무엇입니까? 장점과 단점은 무엇입니까?


Answers



(다음에서 스트라이크 스루 는 C ++ 11에는 더 이상 적용되지 않지만 C ++ 03에는 적용됩니다. C ++ 11은 더 이상 차이가 없습니다. 나는 변명 할 수없는 변호사의 차이).).

명명 된 네임 스페이스는 식별자를 효과적으로 번역 단위 로컬로 만드는 유틸리티입니다. 네임 스페이스에 대해 변환 단위당 고유 한 이름을 선택하는 것처럼 동작합니다.

namespace unique { /* empty */ }
using namespace unique;
namespace unique { /* namespace body. stuff in here */ }

빈 몸체를 사용하는 추가 단계가 중요하므로 using 지시어가 이미 사용 되었기 때문에 네임 스페이스 본문에서 해당 네임 스페이스에 정의 된 ::name 과 같은 식별자를 이미 참조 할 수 있습니다.

즉, 여러 번역 단위에 존재할 수있는 (예를 들어) help 이되는 무료 함수를 가질 수 있으며 링크 시간에 충돌하지 않습니다. 고유 한 네임 스페이스로 인해 고유 한 이름을 가지기 때문입니다 . 그 효과는 식별자 선언에 넣을 수있는 C에서 사용 된 static 키워드를 사용하는 것과 거의 동일합니다. 그런 식으로 사용되는 static 은 C ++에서 더 이상 사용되지 않습니다. 이름없는 네임 스페이스가 타입 변환 유닛을 로컬로 만들 수있는 더 나은 대안이기 때문입니다.

namespace { int a1; }
static int a2;

둘 다 번역 단위로 현지 시간에 충돌하지 않습니다. 하지만 차이점은 익명 네임 스페이스의 a1 이 고유 한 이름을 얻는다는 점입니다. 그것은 여전히 ​​외부 링키지를 가지며 생성 될 오브젝트 파일의 심볼 테이블로 익스포트 될 수 있습니다. 템플릿 인수로 주소를 사용하려면이 작업이 중요합니다.

template<int * ptr> struct sample { };

// OK - a1 has external linkage
sample<&a1> s1; 
// NOT OK - translation unit locality is done by giving a2 internal linkage. 
sample<&a2> s2; 

템플릿 매개 변수에는 외부 링키지가 있어야하므로 식별자는 익명의 네임 스페이스에 넣어야합니다.

comau-computing에서 우수한 기사를 읽으십시오. 정적이 아닌 이름없는 네임 스페이스가 사용되는 이유는 무엇입니까? .




익명 네임 스페이스에 무언가가 있다는 것은이 번역 단위 (.cpp 파일 및 모든 포함)에 대해 로컬임을 의미합니다. 즉, 동일한 이름을 가진 다른 심볼이 다른 곳에 정의되면 ODR ( One Definition Rule) 위반이 발생하지 않습니다.

이것은 정적 전역 변수 또는 정적 함수를 갖는 C 방식과 동일하지만 클래스 정의에도 사용할 수 있습니다 (C ++에서는 static 이 아니라 사용해야합니다).

같은 파일에있는 모든 익명의 네임 스페이스는 동일한 네임 스페이스로 취급되며 서로 다른 파일의 모든 익명의 네임 스페이스는 별개입니다. 익명 네임 스페이스는 다음과 같습니다.

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;



이 예에서는 참여한 프로젝트의 사용자가 익명의 네임 스페이스를 이해하지 못한다는 것을 보여줍니다. :)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

이것들은 익명의 네임 스페이스에있을 필요는 없습니다. 왜냐하면 const 오브젝트는 이미 정적 링크를 가지고 있기 때문에 다른 번역 단위의 동일한 이름의 식별자와 충돌 할 가능성이 없습니다.

    bool getState(userType*,otherUserType*);
}

그리고 이것은 실제로 비관적입니다 : getState() 는 외부 링키지를 가지고 있습니다. 일반적으로 심볼 테이블을 오염시키지 않으므로 정적 링키지를 선호하는 것이 좋습니다. 쓰는 것이 낫다.

static bool getState(/*...*/);

이리. 나는 같은 함정에 빠져 들었습니다. (표준에서 파일 통계는 익명의 네임 스페이스를 사용하는 대신 사용하지 말 것을 제안합니다), KDE와 같은 대규모 C ++ 프로젝트에서 일하면서, 당신의 머리를 바꿔 놓은 사람들이 많이 생깁니다. 다시 주위 :)




이 질문에 대한 다른 대답 외에도 익명의 네임 스페이스를 사용하면 성능을 향상시킬 수 있습니다. 네임 스페이스 내의 심볼은 외부 링키지가 필요 없기 때문에 컴파일러는 네임 스페이스 내에서 코드를 적극적으로 최적화 할 수 있습니다. 예를 들어 루프에서 한 번 여러 번 호출되는 함수는 코드 크기에 영향을 미치지 않고 인라인 될 수 있습니다.

예를 들어, 익명의 네임 스페이스가 사용 된 경우 (x86-64 gcc-4.6.3 및 -O2, add_val의 추가 코드는 컴파일러가 다음을 포함하지 않도록합니다.) 시스템에서 다음 코드는 런타임의 약 70 %를 차지합니다. 두 번).

#include <iostream>

namespace {
  double a;
  void b(double x)
  {
    a -= x;
  }
  void add_val(double x)
  {
    a += x;
    if(x==0.01) b(0);
    if(x==0.02) b(0.6);
    if(x==0.03) b(-0.1);
    if(x==0.04) b(0.4);
  }
}

int main()
{
  a = 0;
  for(int i=0; i<1000000000; ++i)
    {
      add_val(i*1e-10);
    }
  std::cout << a << '\n';
  return 0;
}



익명의 네임 스페이스는 동봉 된 변수, 함수, 클래스 등을 해당 파일 내부에서만 사용할 수있게합니다. 귀하의 예제에서 그것은 전역 변수를 피하는 방법입니다. 런타임 또는 컴파일 시간 성능 차이가 없습니다.

"이 변수, 함수, 클래스 등을 공개 또는 비공개로 설정하길 원합니까?"외에 다른 장점이나 단점은 없습니다.




이름없는 네임 스페이스는 클래스, 변수, 함수 및 객체가 정의 된 파일에 대한 액세스를 제한합니다. 이름 공간 기능은 C / C ++의 static 키워드와 유사합니다.
static 키워드는 전역 변수 및 함수가 정의 된 파일에 대한 액세스를 제한합니다.
명명되지 않은 네임 스페이스와 static 키워드에는 차이가 있기 때문에 static 이 아닌 네임 스페이스가 유리합니다. static 키워드는 변수, 함수 및 객체와 함께 사용할 수 있지만 사용자 정의 클래스에서는 사용할 수 없습니다.
예 :

static int x;  // Correct 

그러나,

static class xyz {/*Body of class*/} //Wrong
static structure {/*Body of structure*/} //Wrong

그러나 명명되지 않은 네임 스페이스에서도 동일한 작업이 가능합니다. 예를 들어,

 namespace {
           class xyz {/*Body of class*/}
           static structure {/*Body of structure*/}
  } //Correct