명명되지 않은 네임 스페이스가 사용되는 이유와 장점은 무엇입니까?


242

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

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

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

명명되지 않은 네임 스페이스를 사용하게 만드는 디자인 고려 사항은 무엇입니까? 장점과 단점은 무엇입니까?

답변:


189

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

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

빈 본문을 사용하는 추가 단계는 중요하므로 ::nameusing 지시문이 이미 수행되었으므로 네임 스페이스 본문 내 에서 해당 네임 스페이스에 정의 된 것과 같은 식별자를 참조 할 수 있습니다 .

help, 여러 번역 단위에 존재할 수있는 무료 기능 (예 :) 을 가질 수 있으며 링크시 충돌하지 않습니다. 이 효과는 static식별자 선언에 넣을 수있는 C 에 사용 된 키워드 를 사용하는 것과 거의 동일합니다 . 명명되지 않은 네임 스페이스는 형식 변환 단위를 로컬로 만들 수도있는 탁월한 대안입니다.

namespace { int a1; }
static int a2;

모두 a의 지역 번역 단위이며, 링크시 충돌하지 않습니다. 그러나 a1익명 네임 스페이스의 고유 한 이름을 얻는다 는 점이 다릅니다 .

comeau-computing에서 훌륭한 기사를 읽으십시오. 왜 정적이 아닌 네임 스페이스가 사용됩니까? ( Archive.org 미러 ).


와의 관계를 설명합니다 static. 당신은 또한 비교할 수 있습니까 __attribute__ ((visibility ("hidden")))?
phinz

74

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

이것은 정적 전역 변수 또는 정적 함수를 갖는 C 방식과 동일하지만 클래스 정의에도 사용할 수 있습니다 ( staticC ++ 대신 사용되어야 함 ).

동일한 파일의 모든 익명 네임 스페이스는 동일한 네임 스페이스로 취급되며 다른 파일의 모든 익명 네임 스페이스는 고유합니다. 익명 네임 스페이스는 다음과 같습니다.

namespace __unique_compiler_generated_identifer0x42 {
    ...
}
using namespace __unique_compiler_generated_identifer0x42;

14

명명되지 않은 네임 스페이스는 클래스, 변수, 함수 및 객체가 정의 된 파일에 대한 액세스를 제한합니다. 명명되지 않은 네임 스페이스 기능은 staticC / C ++의 키워드 와 유사합니다 .
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

13

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

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

#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;
}

5
너무 좋았습니다-나는 gcc 4-1-2에서 네임 스페이스 문을 사용하거나 사용하지 않고 O3 최적화를 사용 하여이 세그먼트를 시도했습니다.
Theo

2
이 코드는 의도적으로 복잡하여 컴파일러가 b와 add_val을 main에 인라인하지 않도록 설득하려고 시도했습니다. O3 최적화는 코딩 비용에 관계없이 많은 인라인을 사용합니다. 그러나 O3가 add_val을 인라인하지 않는 함수가 여전히 있습니다. add_val을 더 복잡하게 만들거나 다른 상황에서 main에서 여러 번 호출 할 수 있습니다.
xioxox

5
@ 다니엘 : 내가 뭘 놓치고 있니? 읽었을 때, 당신은 자신과 비교 -O3했다고 말했고, 3 대 4 초는 "동시"라고 말했습니다. 이들 중 어느 것도 조금 이해가되지 않습니다. 나는 진짜 설명이 의심 되지만 그게 무엇입니까?
underscore_d

@underscore_d 답변 상태 -O2는 -O3이 아니라 두 경우 모두에 사용되었습니다. 다른 최적화 수준이 다르게 동작 할 수 있습니다. 또한 다른 컴파일러 버전이 다르게 동작 할 수 있습니다 (답변이 오래 될 수 있습니다).
Paul Stelian

1
@PaulStelian 나는 그것을 알고 있지만, xioxox의 답변에 답하는 것이 아니라 Theo의 의견에 답하고 있음이 분명합니다 (그의 이름이 변경되었거나 어떻게 든 혼란 스럽지만)
underscore_d

12

이 예는 프로젝트에 참여한 사람들이 익명 네임 스페이스를 이해하지 못함을 보여줍니다. :)

namespace {
    const int SIZE_OF_ARRAY_X;
    const int SIZE_OF_ARRAY_Y;

const객체는 이미 정적 연결을 가지고 있으므로 다른 번역 단위에서 동일한 이름의 식별자와 충돌 할 수 없으므로 익명 네임 스페이스에있을 필요 는 없습니다.

    bool getState(userType*,otherUserType*);
}

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

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

여기. 나는 같은 함정에 빠졌다 (파일 이름은 익명 네임 스페이스를 선호하여 더 이상 사용되지 않는다고 제안하는 표준이 있지만 KDE와 같은 대형 C ++ 프로젝트에서 작업하면 많은 사람들이 머리를 바르게 돌린다. 다시 주위에 :)


10
C ++ 11 명명 네임은 내부 링크 (또는 표준의 섹션 3.5 갖기 때문에 en.cppreference.com/w/cpp/language/namespace#Unnamed_namespaces )
에밀 Vrijdags

11
하지만 여전히, 그들의 의미의 시각적 신호로, 하나에 넣어하고 (더) 사소한 제거하려면 그것을 만들 다치게하지 않습니다 - 확실히 기술적으로, "이러한 익명의 이름 공간에있을 필요가 없다" const다움을 원하는 경우 나중에. OP의 팀이 "알지 못한다"는 것을 의미합니다. 또한 외부 연결이있는 익명 네임 스페이스의 함수에 대한 내용은 C ++ 11부터 잘못되었습니다. 내 이해로 이전에는 외부 연결이 필요한 템플릿 인수 문제를 수정 했으므로 명명되지 않은 네임 스페이스 (템플릿 인수를 포함 할 수 있음)에 내부 연결이 허용 될 수 있습니다.
underscore_d

11

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

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


2
성능 차이가있을 수 있습니다-여기 내 답변을 참조하십시오. 컴파일러가 코드를 더 잘 최적화 할 수 있습니다.
xioxox

2
당신은 요점을 가지고 있습니다. 적어도 오늘 C ++까지는 요. 그러나 C ++ 98 / C ++ 03에서는 템플릿 인수로 사용하기 위해 외부 연결이 필요했습니다. 익명 네임 스페이스의 항목은 템플릿 인수로 사용할 수 있으므로 파일 외부에서 참조 할 수있는 방법이 없어도 외부 연결 (적어도 C ++ 11 이전 버전)이 있습니다. 나는 표준에 따라 규칙이 시행 된 것처럼 행동하기 만하면되기 때문에 퍼지 할 능력이 있다고 생각한다. 규칙을 실제로 시행하지 않고도 그렇게 할 수 있습니다.
Max Lybbert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.