태그 보관물: namespaces

namespaces

std 네임 스페이스 사용 ‘ std::’ 와

std 네임 스페이스와 관련하여 ‘사용’을 사용하는 데 다른 견해가있는 것 같습니다.

어떤 사람들은 ‘ using namespace std‘를 사용한다고 말하고 , 다른 사람들은 ‘ std::‘ 와 함께 사용할 std 함수를 접두사로 말하고 다른 사람들은 다음과 같이 사용한다고 말합니다.

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;

사용할 모든 표준 함수에 대해.

각각의 장단점은 무엇입니까?



답변

대부분의 C ++ 사용자는 아주 만족 읽고 std::string, std::vector원시보고, 사실 등 vector이있는 경우 궁금한데을 std::vector하거나 다른 사용자 정의 vector.

나는 항상 using namespace std;. 모든 종류의 이름을 전역 네임 스페이스로 가져 오며 모든 종류의 명확하지 않은 모호성을 유발할 수 있습니다.

다음은 std네임 스페이스 에있는 몇 가지 일반적인 식별자입니다 . 개수, 정렬, 찾기, 같음, 역방향. 지역 변수라는 데 count의미 using namespace std사용할 수 없습니다 count대신을 std::count.

원치 않는 이름 충돌의 전형적인 예는 다음과 같습니다. 당신이 초보자이고에 대해 모른다고 상상해보십시오 std::count. 다른 것을 사용하고 <algorithm>있거나 관련이없는 것처럼 보이는 헤더에 의해 끌어 온다고 상상해보십시오 .

#include <algorithm>
using namespace std;

int count = 0;

int increment()
{
    return ++count; // error, identifier count is ambiguous
}

std::count일부 긴 중첩 유형이있는 템플릿 이므로 오류는 일반적으로 길고 비 친화적 입니다.

그래도 괜찮 std::count습니다. 글로벌 네임 스페이스로 들어가고 함수 개수가이를 숨기기 때문입니다.

#include <algorithm>
using namespace std;

int increment()
{
    static int count = 0;
    return ++count;
}

약간 놀랍게도 이것은 괜찮습니다. 선언적 범위로 가져온 식별자는 정의 된 위치와 가져온 위치를 모두 포함하는 공통 네임 스페이스에 나타납니다. 즉, std::countcount전역 네임 스페이스에서와 같이 표시 되지만 increment.

#include <algorithm>

int increment()
{
    using namespace std;
    static int count = 0;
    return ++count;
}

그리고 비슷한 이유로 count여기에서 모호합니다. using namespace std발생하지 않습니다 std::count, count예상대로 외부 를 숨 깁니다 . using namespace그 규칙 수단 std::count보이는합니다 (의 increment역할)이 동일한 범위의 전역, 즉에서 선언 된 것처럼 int count = 0;따라서 모호성을 일으키고.

#include <algorithm>

int count = 0;

int increment()
{
    using namespace std;
    return ++count; // error ambiguous
}


답변

기본 사항 제외 (모든 stl 객체 / 함수 앞에 std ::를 추가해야하며 ‘using namespace std’가없는 경우 충돌 가능성이 적음)

절대로 넣어서는 안된다는 점도 주목할 가치가 있습니다.

using namespace std

헤더 파일에서 해당 네임 스페이스를 사용하지 않더라도 해당 헤더 파일을 포함하는 모든 파일에 전파 할 수 있습니다.

어떤 경우에는 다음과 같은 것을 사용하는 것이 매우 유익합니다.

using std::swap

특수한 스왑 버전이있는 것처럼 컴파일러는이를 사용하고 그렇지 않으면 std::swap.

를 호출 std::swap하면 항상 기본 버전을 사용하며 최적화 된 버전 (존재하는 경우)을 호출하지 않습니다.


답변

첫째, 몇 가지 용어 :

  • using-declaration : using std::vector;
  • 지시어 사용 : using namespace std;

헤더 파일의 전역 범위에서 사용되지 않는 한 using-directives 를 사용 하는 것이 좋습니다. 그래서

using namespace std;

.cpp 파일에있는 것은 실제로 문제가되지 않으며, 문제가있는 것으로 밝혀지면 완전히 제어 할 수 있습니다 (원하는 경우 특정 블록으로 범위를 지정할 수도 있음). 수많은 std::한정자로 코드를 어지럽히는 특별한 이유는 없습니다. 단지 시각적 노이즈가됩니다. 그러나 std코드 에서 네임 스페이스 의 전체 이름을 사용하지 않는 경우 지시문을 생략해도 문제가 없습니다. 그것은 팽팽한 것입니다. 지시가 필요하지 않다면 그것을 사용할 필요가 없습니다.

마찬가지로 네임 스페이스의 특정 유형에 대해 몇 가지 using-declaration ( using-directives 대신)을 사용할std 수 있다면 해당 특정 이름 만 현재 네임 스페이스로 가져 오지 말아야 할 이유가 없습니다. 마찬가지로, 단일 using-directive가 트릭을 수행 할 때 25 또는 30 개의 using-declaration을 갖는 것은 미친 짓이고 부기 번거로울 것이라고 생각합니다.

그것은 당신이 항상 있다는 것을 명심하는 것이 좋다 해야한다 사용하여 선언을 사용. Effective C ++, Third Edition에서 Scott Meyers의 “항목 25 : 던지지 않는 스왑에 대한 지원 고려”를 참조하십시오. 일반적인 템플릿 함수가 매개 변수화 된 유형에 대해 ‘최상의’스왑 메서드를 사용하도록하려면 using-declaration 및 인수 종속 조회 (일명 ADL 또는 Koenig 조회)를 사용해야합니다.

template< typename T >
void foo( T& x, T& y)
{
    using std::swap;     // makes std::swap available in this function

    // do stuff...

    swap( x, y);         // will use a T-specific swap() if it exists,
                         //  otherwise will use std::swap<T>()

    // ...
 }

네임 스페이스를 많이 사용하는 다양한 언어의 공통 관용구를 살펴 봐야한다고 생각합니다. 예를 들어 Java 및 C #은 네임 스페이스를 광범위하게 사용합니다 (C ++보다 더 많이 사용됨). 네임 스페이스 내의 이름이 해당 언어에서 사용되는 가장 일반적인 방법은 using-directive에 해당하는 것과 함께 한꺼번에 현재 범위로 가져 오는 것입니다. 이것은 광범위한 문제를 일으키지 않으며, 문제가되는 몇 번은 정규화 된 이름을 통해 문제의 이름을 처리하거나 별칭을 지정하여 ‘예외’기준으로 처리됩니다. C ++에서 수행 할 수있는 것처럼.

Herb Sutter와 Andrei Alexandrescu는 “Item 59 : Do n’t write namespace usings in a header file or before an #include”of their book, C ++ Coding Standards : 101 Rules, Guidelines, and Best Practices :

요컨대 : 지시문 뒤에 구현 파일에서 선언과 지시문을 자유롭게 사용하여 네임 스페이스를 사용할 수 있고 사용해야 #include합니다. 반대로 반복되는 주장에도 불구하고 선언과 지시문을 사용하는 네임 스페이스는 악의가 없으며 네임 스페이스의 목적을 무너 뜨리지 않습니다. 오히려 네임 스페이스를 사용 가능하게 만듭니다.

Stroupstrup은 “The C ++ Programming Language, Third Edition”에서 “글로벌 네임 스페이스를 오염시키지 마십시오”라는 말로 자주 인용됩니다. 그는 실제로 (C.14 [15])라고 말하지만 C.10.1 장에서 다음과 같이 말합니다.

사용 선언은 로컬 영역에 이름을 추가한다. 사용-지시어는 하지 않습니다; 단순히 선언 된 범위에서 액세스 가능한 이름을 렌더링합니다. 예를 들면 :

namespaceX {
    int i , j , k ;
}

int k ;
void f1()
{
    int i = 0 ;

    using namespaceX ; // make names from X accessible

    i++; // local i
    j++; // X::j
    k++; // error: X::k or global k ?

    ::k ++; // the global k

    X::k ++; // X’s k
}

void f2()
{
    int i = 0 ;

    using X::i ; // error: i declared twice in f2()
    using X::j ;
    using X::k ; // hides global k

    i++;
    j++; // X::j
    k++; // X::k
}

로컬로 선언 된 이름 (일반 선언 또는 using-declaration에 의해 선언 됨)은 동일한 이름의 로컬이 아닌 선언을 숨기고 선언 지점에서 이름의 불법적 인 오버로딩이 감지됩니다.

대한 모호성 오류를 참고 k++에서
f1(). 전역 이름은 전역 범위에서 액세스 할 수있는 네임 스페이스의 이름보다 우선하지 않습니다. 이는 우발적 인 이름 충돌에 대한 상당한 보호를 제공하며, 중요한 것은 전역 네임 스페이스를 오염시켜 얻을 수있는 이점이 없음을 보장합니다.

많은 이름을 선언하는 라이브러리가 using-directive를 통해 액세스 가능하도록 만들 때 사용하지 않는 이름의 충돌이 오류로 간주되지 않는다는 것이 중요한 이점입니다.

기존의 C 및 C ++ 프로그램에 비해 네임 스페이스를 사용하는 새 프로그램에서 전역 이름 사용이 급격히 줄어들기를 바랍니다. 네임 스페이스에 대한 규칙은 전역 범위를 오염시키지 않도록주의하는 사람보다 전역 이름의“게으른 ”사용자에게 이점을 제공하지 않도록 특별히 제작되었습니다.

그리고 ‘글로벌 이름의 게으른 사용자’와 같은 이점이있는 이유는 무엇입니까? using-directive를 활용 하여 네임 스페이스의 이름을 현재 범위에서 안전하게 사용할 수 있도록합니다.

std사용 지시문 (뒤에 지시문을 배치하여)을 적절히 사용하여 범위에서 사용할 수 있는 네임 스페이스 의 이름은 전역 네임 스페이스를 오염 #includes시키지 않습니다 . 그 이름을 쉽게 사용할 수 있고 충돌에 대한 지속적인 보호를 제공합니다.


답변

헤더 파일의 전역 범위에서 네임 스페이스를 사용하지 마십시오. 이로 인해 충돌이 발생할 수 있으며 충돌이 발생한 파일의 책임자는 원인을 제어 할 수 없습니다.

구현 파일에서 선택은 훨씬 덜 잘립니다.

  • using 네임 스페이스 std를 넣으면 해당 네임 스페이스의 모든 기호를 가져옵니다. 추가 될 기호에 대해 말하지 않고는 거기에있는 모든 기호를 아는 사람이 거의 없기 때문에 (따라서 충돌이없는 정책을 실제로 적용하는 것은 불가능합니다) 문제가 될 수 있습니다. 그리고 C ++ 표준에서는 헤더가 다른 헤더의 기호를 추가 할 수 있습니다 (C에서는 허용하지 않음). 통제 된 케이스에서 쓰기를 단순화하기 위해 실제로는 여전히 잘 작동 할 수 있습니다. 그리고 오류가 발생하면 문제가있는 파일에서이를 감지합니다.

  • std :: name을 사용하여 퍼팅; 알 수없는 기호를 가져올 위험없이 쓰기가 간단하다는 장점이 있습니다. 비용은 원하는 모든 기호를 명시 적으로 가져와야한다는 것입니다.

  • 명시 적으로 자격을 갖추면 약간의 혼란이 더해 지지만 연습 문제가 적다고 생각합니다.

내 프로젝트에서는 모든 이름에 대해 명시 적 자격을 사용하고, std :: name 사용을 수락하고, std 네임 스페이스 사용에 반대합니다 (우리는 자체 목록 유형이있는 lisp 인터프리터가 있으므로 충돌이 확실합니다).

다른 네임 스페이스의 경우 사용되는 명명 규칙도 고려해야합니다. 이름에 네임 스페이스 (버전 관리 용)와 접두사를 사용하는 프로젝트를 알고 있습니다. using namespace Xthen을 수행하는 것은 거의 위험이 없으며 그렇게하지 않으면 코드가 어리석게 보입니다 PrefixNS::pfxMyFunction(...).

기호를 가져 오려는 경우가 있습니다. std :: swap이 가장 일반적인 경우입니다. std :: swap을 가져온 다음 정규화되지 않은 스왑을 사용합니다. 인수 종속 조회는 유형의 네임 스페이스에서 적절한 스왑이있는 경우이를 찾고없는 경우 표준 템플릿으로 대체합니다.


편집하다:

댓글에서 Michael Burr는 충돌이 현실 세계에서 발생하는지 궁금합니다. 여기에 실제 사례가 있습니다. 확장 언어는 lisp 방언입니다. 인터프리터에는 포함 파일 lisp.h가 있습니다.

typedef struct list {} list;

우리는 다음과 같은 코드 ( “엔진”이라고 부를 것입니다)를 통합하고 수정해야했습니다.

#include <list>
...
using std::list;
...
void foo(list const&) {}

그래서 우리는 다음과 같이 수정했습니다.

#include <list>

#include "module.h"
...
using std::list;
...
void foo(list const&) {}

좋은. 모든 것이 작동합니다. 몇 달 후, “module.h”는 “list.h”를 포함하도록 수정되었습니다. 테스트를 통과했습니다. “모듈”은 ABI에 영향을 미치는 방식으로 수정되지 않았으므로 “엔진”라이브러리는 사용자를 다시 컴파일하지 않고도 사용할 수 있습니다. 통합 테스트는 괜찮 았습니다. 새 “모듈”이 게시되었습니다. 코드가 수정되지 않았을 때 엔진의 다음 컴파일이 중단되었습니다.


답변

코드에서 std 및 기타 라이브러리와 이름이 충돌 할 위험이 없다면 다음을 사용할 수 있습니다.

using namespace std;

그러나 문서화에 대한 코드의 종속성을 정확하게 알고 싶거나 이름 충돌의 위험이있는 경우 다른 방법을 사용하십시오.

using std::string;
using std::cout;

세 번째 솔루션은 이러한 솔루션을 사용하지 말고 std :: 코드를 사용할 때마다 더 많은 보안을 제공하지만 코드가 약간 무거울 수 있습니다.


답변

양자 모두

using std::string;

using namespace std;

전역 네임 스페이스에 일부 기호 (하나 또는 여러 개)를 추가합니다. 그리고 전역 네임 스페이스에 심볼을 추가 하는 것은 헤더 파일에서 절대로 하지 말아야 할 일입니다. 헤더를 포함 할 사람을 제어 할 수 없으며 다른 헤더를 포함하는 많은 헤더 (및 헤더 등을 포함하는 헤더를 포함하는 헤더 …)가 있습니다.

구현 (.cpp) 파일에서 그것은 당신에게 달려 있습니다 ( 모든 #include 지시문 후에 해야한다는 것을 기억하십시오 ). 이 특정 파일의 코드 만 분리 할 수 ​​있으므로 이름 충돌의 원인을 관리하고 찾기가 더 쉽습니다. 식별자 앞에 std : 🙁 또는 다른 접두사, 프로젝트에 많은 네임 스페이스가있을 수 있음)를 선호하는 경우 괜찮습니다. 사용하는 식별자를 전역 네임 스페이스에 추가하고 싶다면 괜찮습니다. 전체 네임 스페이스를 머리에 가져오고 싶다면 :-), 그것은 당신에게 달려 있습니다. 효과는 단일 컴파일 단위로 제한되지만 허용됩니다.


답변

저에게는 ::가능 하면 사용하는 것을 선호 합니다.

std::list<int> iList;

나는 쓰기 싫어 :

for(std::list<int>::iterator i = iList.begin(); i != iList.end(); i++)
{
    //
}

바라건대, C ++ 0x를 사용하면 다음과 같이 작성할 수 있습니다.

for(auto i = iList.begin(); i != iList.end(); i++)
{
    //
}

네임 스페이스가 매우 길면

namespace dir = boost::filesystem;

dir::directory_iterator file("e:/boost");
dir::directory_iterator end;

for( ; file != end; file++)
{
    if(dir::is_directory(*file))
        std::cout << *file << std::endl;
}