c++ - 충돌 - xcode using namespace




왜 "using namespace std"가 나쁜 습관으로 간주됩니까? (20)

다른 사람들이 코드에서 using namespace stdusing namespace std 작성 using namespace std 것이 잘못되었다는 말을 std::cout , 대신 std::coutstd::cin 직접 사용해야합니다.

using namespace std 하는 것이 나쁜 습관으로 간주됩니까? 비효율적입니까 아니면 모호한 변수 ( std 네임 스페이스의 함수와 같은 이름을 공유하는 변수)를 선언 할 위험이 있습니까? 성능에 영향을 줍니까?


세계적으로 사용하지 마십시오.

세계적으로 사용될 때만 "나쁜"것으로 간주 됩니다 . 때문에:

  • 프로그래밍중인 네임 스페이스를 혼란스럽게 만듭니다.
  • 독자는 using namespace xyz 많이 using namespace xyz 하는 경우 특정 식별자의 출처를보기가 어려울 것입니다.
  • 소스 코드의 다른 독자들에게 사실이 무엇이든, 가장 자주 읽는 독자에게는 더욱 사실입니다. 1, 2 년 후에 돌아와보세요 ...
  • using namespace stdusing namespace std 것에 관해서 만 이야기한다면, 당신이 가진 모든 것을 알아 채지 못할 수도 있습니다. 또 다른 #include 를 추가하거나 새로운 C ++ 리비전으로 이동할 때 여러분은 알지 못했던 이름 충돌을 일으킬 수 있습니다.

로컬로 사용할 수 있습니다.

계속해서 로컬에서 (거의) 자유롭게 사용하십시오. 이것은 물론, std:: 를 반복하지 못하게합니다. - 반복은 나쁘다.

로컬에서 사용하기위한 관용구

C ++ 03에는 클래스에 swap 함수를 구현하는 관용구 (상용구 코드)가있었습니다. using namespace std 사용하는 로컬을 using namespace std 하거나 최소한 using std::swap 사용하는 것이 좋습니다.

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

이것은 다음과 같은 마술을합니다 :

  • 컴파일러는 value_ 에 대한 std::swap , 즉 void std::swap(int, int) 합니다.
  • 과부하 void swap(Child&, Child&) 구현하면 컴파일러가이를 선택합니다.
  • 오버로드가 없다면 컴파일러는 void std::swap(Child&,Child&) 을 사용하여 최상의 스왑 핑을 시도 할 것입니다.

C ++ 11에서는이 패턴을 더 이상 사용할 이유가 없습니다. std::swap 의 구현이 변경되어 잠재적 인 과부하를 찾아 선택했습니다.


  1. 당신은 당신보다 다른 스타일과 베스트 프랙티스 의견을 가진 사람들이 작성한 코드를 읽을 수 있어야합니다.

  2. 당신이 단지 법정을 사용하고 있다면, 아무도 혼란스러워하지 않습니다. 하지만 주위에 많은 네임 스페이스가 있고이 클래스를 볼 때 네임 스페이스가 어떤 역할을하는지 정확히 알지 못하는 경우 네임 스페이스를 명시 적으로 주석으로 사용해야합니다. 언뜻보기에 '오, 이것은 파일 시스템 작업입니다'또는 '네트워크 작업을하는 것'입니다.


나는 또한 그것을 나쁜 습관이라고 생각한다. 왜? 언젠가 나는 네임 스페이스의 기능이 모든 것을 하나의 글로벌 백으로 던져 버리지 않도록 물건을 나눌 것이라고 생각했습니다. 그러나 'cout'과 'cin'을 자주 사용하면 다음과 같이 작성합니다. using std::cout; using std::cin; using std::cout; using std::cin; cpp 파일에서 (헤더 파일에 #include 와 함께 전파되지 않음). 아무도 제정신이 아닐 것입니다. ;)


나는 최근 Visual Studio 2010 에 대한 불만을 접했습니다. 거의 모든 소스 파일에는 다음과 같은 두 줄이 있습니다.

using namespace std;
using namespace boost;

Boost 기능은 C ++ 0x 표준에 포함되어 있으며 Visual Studio 2010에는 C ++ 0x 기능이 많이 포함되어 있으므로이 프로그램은 갑자기 컴파일되지 않았습니다.

따라서 using namespace X; 피하십시오 using namespace X; 미래의 검증의 한 형태이며, 사용중인 라이브러리 및 / 또는 헤더 파일을 변경하여 프로그램을 중단시키지 않는지 확인하는 방법입니다.


동시에 많은 네임 스페이스를 사용하는 것은 분명히 재앙에 대한 처방입니다.하지만 JUST 네임 스페이스 std 와 네임 스페이스 std 사용하는 것은 내 의견으로는 크지 않습니다. 왜냐하면 재정의는 자신의 코드에서만 발생할 수 있기 때문입니다 ...

따라서 함수를 "int"나 "class"와 같은 예약 된 이름으로 간주하면됩니다.

사람들은 그것에 대해 너무 항문하는 것을 멈춰야합니다. 네 선생님이 옳았 어. 그냥 네임 스페이스를 사용하십시오. 그것은 네임 스페이스를 사용하는 첫 번째 지점입니다. 동시에 둘 이상을 사용하지 않아야합니다. 그것이 당신 자신이 아니라면. 다시 말하면, 재정의는 일어나지 않을 것입니다.


또 다른 이유는 놀라움입니다.

만약 내가 cout << blah 보게되면, 대신 std::cout << blah

이게 뭐지? 정상적인 것입니까? 뭔가 특별한가요?


숙련 된 프로그래머는 문제를 해결하는 모든 것을 사용하고 새로운 문제를 만드는 것을 피하고 이러한 정확한 이유 때문에 헤더 파일 수준의 지시문 사용을 피합니다.

숙련 된 프로그래머는 또한 소스 파일 내에서 이름의 완전한 자격을 피하려고합니다. 이것에 대한 사소한 이유 는 적절한 이유가없는 한 코드가 적을 때 더 많은 코드를 작성하는 것이 우아 하지 않다는 입니다. 이것의 주된 이유는 ADL (argument-dependent lookup)을 끄는 것입니다.

이러한 좋은 이유 는 무엇입니까? 때로는 프로그래머가 명시 적으로 ADL을 끄고 싶을 때도 있으며, 다른 경우에는 모호성을 원하고 있습니다.

그래서 다음은 괜찮습니다.

  1. 함수의 구현 내에서 함수 수준 using 지시문 및 using 사용
  2. 소스 파일 내부의 선언을 사용하는 소스 파일 레벨
  3. (때로는) source-file-level using-directives

올바른 헤더 파일을 가져 오는 경우 갑자기 전역 범위에서 hex , left , plus 또는 count plus 같은 이름을 갖게됩니다. std:: 가이 이름을 가지고 있다는 것을 모르는 경우 이것은 놀라운 일입니다. 이 이름을 로컬로 사용하려고하면 혼동이 생길 수 있습니다.

모든 표준 항목이 자체 네임 스페이스에 있으면 코드 또는 다른 라이브러리와의 이름 충돌에 대해 걱정할 필요가 없습니다.


전 세계적으로 사용해서는 안되는 데 동의하지만 namespace 와 같이 로컬에서 사용하는 것은 그리 좋지 않습니다. 다음은 "The C ++ Programming Language" 의 예제입니다.

namespace My_lib {

    using namespace His_lib; // everything from His_lib
    using namespace Her_lib; // everything from Her_lib

    using His_lib::String; // resolve potential clash in favor of His_lib
    using Her_lib::Vector; // resolve potential clash in favor of Her_lib

}

이 예에서 우리는 잠재적 인 이름 충돌과 해당 구성으로 인해 발생하는 모호성을 해결했습니다.

His_lib::String 과 같은 His_lib::String 선언에 의해 선언 된 이름을 포함하여 명시 적으로 선언 된 이름은 using-directive ( using namespace Her_lib )에 의해 다른 범위에서 액세스 가능한 이름보다 우선합니다.


중히 여기다

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // uh oh
};

이것은 간단한 예입니다. 20 개의 include와 다른 import가있는 파일이 있으면 문제를 파악하기 위해 많은 의존성이 있습니다. 더 나쁜 것은 충돌하는 정의에 따라 다른 모듈에서 관련없는 오류를 얻을 수 있다는 것입니다.

그것은 끔찍한 것이 아니지만 헤더 파일이나 전역 네임 스페이스에서 두통을 사용하지 않아도됩니다. 아주 제한된 범위에서 처리하는 것이 좋을지 모르지만 내 기능이 어디에서 오는지 명확히하기 위해 추가로 5자를 입력하는 데 문제가 없었습니다.


코드를보고 그 코드가 무엇인지 알면 좋습니다. std::cout 을 보면 std 라이브러리의 cout 스트림이라는 것을 알 수 있습니다. 만약 내가 그걸 보았다면 나는 모른다. std 라이브러리의 cout 스트림이 될 수 있습니다. 또는 int cout = 0; 동일한 기능에서 10 줄 높습니다. 또는 해당 파일에서 cout 이라는 static 변수. 그것은 무엇이든 수 있습니다.

지금은별로 크지 않은 백만 줄의 코드베이스를 가져 와서 버그를 찾고 있습니다. 즉,이 라인에 100 만 줄에 한 줄이 있다는 것을 의미합니다. cout << 1; cout 이라는 static int 읽고, 왼쪽으로 한 비트 씩 이동하여 그 결과를 버릴 수 있습니다. 버그를 찾으려면 그걸 확인해야합니다. 내가 정말로 std::cout 을보기를 정말로 좋아하는지 어떻게 알 수 있습니까?

당신이 교사이고 생계를위한 코드를 작성하고 유지할 필요가 없다면 정말 좋은 생각 인 것 중 하나입니다. 나는 코드를 보는 것을 좋아한다. (1) 내가하는 일을 안다. 그리고 (2) 나는 그것을 쓰는 사람이 자신이하는 일을 알고 있다고 확신한다.


클래스의 헤더 파일에 using namespaceusing namespace 하는 문제는 헤더 파일을 포함하여 클래스를 사용하려는 사람이 다른 네임 스페이스의 '사용'(즉, 모든 것을 볼 수 있음)을 강요한다는 것입니다.

그러나 using 문을 (개인) * .cpp 파일에 자유롭게 넣을 수는 있습니다.

어떤 사람들은 내 말을 "좋아하지 말라"는 것에 동의하지 않는다는 것을 알아 두십시오. 왜냐하면 cpp 파일의 using 문이 (헤더 파일을 포함하는 사람들에게 영향을 미치지 않기 때문에) 헤더에있는 것보다 낫지 만, 그들은 여전히 (코드에 따라 클래스의 구현을 유지하기가 더 어려워 질 수 있기 때문에) 좋지 않습니다. 이 FAQ 주제에 따르면,

use-directive는 레거시 C ++ 코드에 존재하며 네임 스페이스로 쉽게 전환 할 수 있지만 적어도 새로운 C ++ 코드에서는 사용하지 않는 것이 좋습니다.

FAQ는 두 가지 대안을 제안합니다 :

  • 사용 선언 :

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • 그냥 표준 입력 ::

    std::cout << "Values:";
    

네임 스페이스 std를 사용하는 예제는 알고리즘 라이브러리의 함수이기도 한 count의 모호함으로 인해 complilation 오류를 발생시킵니다.

#include <iostream>

using namespace std;

int count = 1;
int main() {
    cout<<count<<endl;
}

여기서 다른 사람들과 동의하지만 가독성과 관련된 문제를 해결하고 싶습니다. 파일, 함수 또는 클래스 선언의 맨 위에 typedef를 사용하면이 모든 것을 피할 수 있습니다.

클래스의 메소드는 비슷한 데이터 유형 (멤버)을 다루는 경향이 있고 typedef는 클래스의 컨텍스트에서 의미있는 이름을 할당 할 수있는 기회이기 때문에 일반적으로 클래스 선언에 사용합니다. 이것은 실제로 클래스 메소드의 정의에서 가독성을 돕습니다.

//header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

구현시 :

//cpp
Lines File::ReadLines()
{
    Lines lines;
    //get them...
    return lines;
}

반대로 :

//cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    //get them...
    return lines;
}

또는:

//cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    //get them...
    return lines;
}

귀하의 질문에 대답하기 위해 나는이 방법을 실질적으로 본다 : 많은 프로그래머가 (모두는 아님) 네임 스페이스 표준을 호출한다. 그러므로 네임 스페이스 std에있는 것과 동일한 이름을 사용하거나 사용하는 것을 사용하지 않는 습관이 있어야합니다. 그것은 엄청난 거래이지만, 엄밀히 말하면 가능한 일관된 단어와 가명의 수와 너무 많이 비교되지는 않습니다.

내 말은 ... 정말로 "존재하는 것에 의지하지 말라"는 말은 당신이 존재하지 않는다는 것을 의지하는 것입니다. 코드 스 니펫을 빌려 지속적으로 복구하는 문제가 끊임없이 발생합니다. 제한된 범위에서 사용자 정의 및 빌린 물건을 그대로 유지하고 전역과 함께 매우 절약하십시오 (정직하게 말해서 전역 변수는 거의 나중에 "컴파일하고 나중에 온전한"목적으로 사용해야합니다). 정말 std를 사용하면 "cout"과 "std :: cout"모두에서 작동하기 때문에 선생님의 조언은 좋지 않다고 생각하지만 std를 사용하지 않으면 "std :: cout"에서만 작동합니다. 자신 만의 모든 코드를 작성할만큼 운이 좋은 것은 아닙니다.

참고 : 컴파일러의 작동 방식에 대해 조금 배우기 전까지는 효율성 문제에 너무 집중하지 마십시오. 코딩 경험이 적 으면 좋은 코드를 무언가로 간단하게 일반화 할 수 있는지 알기 전에 코딩을 많이 배울 필요가 없습니다. C로 모든 것을 쓴 것처럼 간단합니다. 좋은 코드는 복잡 할뿐입니다.


나는 다른 사람들과 동의한다 - 그것은 이름 충돌, 애매함을 요구하고있다. 그리고 사실 그것은 덜 명백하다. 내가 볼 수있는 동안 using, 나의 개인적인 취향은 그것을 제한하는 것이다. 나는 또한 다른 사람들이 지적한 것을 강력히 고려할 것이다.

꽤 일반적인 이름 일 수있는 함수 이름을 찾고 싶지만 std네임 스페이스 에서만 찾을 수있는 함수 이름을 찾으려면 (또는 그 반대의 경우 - 네임 스페이스 std, 네임 스페이스 등의 모든 호출을 변경하려는 경우 X) 그렇다면이 일을 어떻게 제안합니까? 프로젝트를 작성하는 프로그램을 작성할 수는 있지만 프로젝트를 유지 관리하는 프로그램을 작성하는 것보다는 프로젝트 자체에 대한 작업을하는 것이 더 좋지 않습니까?

개인적으로 나는 실제로 std::접두사에 신경 쓰지 않습니다 . 나는 그것을 가지고 있지 않은 것보다 더 많은 것을 좋아한다. 명시 적이며 "이 코드는 내 코드가 아닙니다 ... 표준 라이브러리를 사용하고 있습니다."또는 다른 코드 일 경우 그 코드가 더 좋은지는 모르겠다 고 생각합니다. 이것은 내가 최근에 C ++에 들어갔을 때 이상 할 수도 있습니다. (C 및 다른 언어를 훨씬 오래 사용하고 C는 어셈블리보다 항상 좋아하는 언어입니다.)

위의 내용과 다소 관련이 있지만 다른 사람들이 지적하고있는 것은 다른 것이 하나 있습니다. 이것이 나쁜 실행 일지 모르지만, 때로는 std::name프로그램 별 구현을위한 표준 라이브러리 버전과 이름을 예약 합니다. 네, 사실 이걸로 당신을 물들 일 수 있고 열심히 물지 만 처음부터이 프로젝트를 시작 했으니까요. 나는 그걸위한 유일한 프로그래머입니다. 예 : 오버로드 std::string하여 호출합니다 string. 도움이되는 추가 사항이 있습니다. 나는 C와 Unix (+ Linux) 경향 때문에 소문자를 사용했다.

그 외에도 네임 스페이스 별칭을 사용할 수 있습니다. 다음은 참조되지 않았을 때 유용했던 예제입니다. 나는 C ++ 11 표준과 특히 libstdc ++를 사용한다. 글쎄, 완전한 std::regex지원을 하지 못했다 . 물론 컴파일되지만 프로그래머가 끝내면 오류가되는 줄을 따라 예외가 발생합니다. 그러나 구현이 부족합니다. 그래서 여기 그것이 내가 어떻게 해결되었는지입니다. Boost의 정규식을 설치하고 링크를합니다. 그러면 libstdc ++가 완전히 구현되었을 때이 블록을 제거하면되고 코드는 그대로 유지됩니다.

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;  
}

나는 이것이 나쁜 생각인지 아닌지에 대해 논쟁하지 않을 것이다. 그러나 그것은 그것이 내 프로젝트에 대해 깨끗하게 유지하고 동시에 그것을 구체적으로 만든다고 주장 할 것입니다 : 사실 부스트를 사용해야합니다. 그러나 libstdc ++처럼 결국 사용하게 될 것입니다. 예. 자신의 프로젝트를 시작하고 처음부터 표준 (...)으로 시작하는 것은 유지 보수, 개발 및 프로젝트와 관련된 모든 것을 돕는 아주 먼 길을갑니다!

편집하다:
이제 시간이 생겨서 뭔가를 분명히했습니다. 나는 실제로 STL에서 수업의 이름을 / 고의로 더 구체적으로 대신 사용하는 것이 좋은 생각이라고 생각하지 않습니다. 문자열은 'String'에 대한 아이디어가 마음에 들지 않았으므로 예외적으로 (여기서는 첫 번째, 위 또는 두 번째를 무시하고 꼭 필요한 경우 말장난) 사용합니다. 그것이 그렇듯이, 저는 여전히 C에 편향되어 있고 C ++에 편향되어 있습니다. 내가하는 일 중 많은 부분을 아끼지 않는 것은 C 다. (하지만 그것은 좋은 운동이었고 다른 언어를 배우고 b. 객체 / 클래스 / 기타에 대해 덜 편향되지 않도록 노력했다. 덜 닫힌 마음, 덜 오만한 것, 받아들이는 것). 그러나 유용한 것은 이미 제안 된 것들이 있습니다 : 저는 실제로 목록을 사용합니다 (꽤 일반적입니다, 그렇지 않습니까?).내가 할 수있는 경우 이름 충돌을 일으킬 두 가지 이름을 정렬 (똑같은)using namespace std;그래서 그 목표를 향해서 나는 구체적이고, 통제력 있고, 표준적인 사용을 원한다면 그것을 명시해야한다는 것을 알고 있습니다. 간단히 말하면 : 허용되지 않는다.

그리고 Boost의 정규 표현식을 만드는 부분에 대해서 std. 나는 미래의 통합을 위해 그런 일을합니다. 다시, 저는 이것이 편견이라고 완전히 인정합니다. 저는 그것이 boost::regex:: ...참으로 나 만큼의 추악한 생각을하지 않습니다. 그것은 나를위한 또 다른 일입니다. C ++에는 많은 것들이 있습니다. 아직 외모와 방법을 완전히 받아 들여야 만합니다 (또 다른 예 : varadic 대 var args [가변성 템플릿은 매우 유용합니다!]). 내가 받아들이는 사람들조차도 어려웠고 아직도 그들과 문제가 있습니다.


내 경험으로 말하면서 여러 개의 라이브러리를 사용한다면 cout,하지만 다른 목적으로는 틀린 것을 사용할 수 있습니다 cout.

내가 입력, 예를 들어, using namespace std;using namespace otherlib;및보다는, (둘 다 될 일이있는) 단지 cout을 입력 std::cout(또는 'otherlib::cout'), 당신은 잘못 하나를 사용하고, 오류를 얻을 수 있습니다, 그것은 훨씬 더 효과적이고 사용하는 것이 효율적입니다 std::cout.


소프트웨어 나 프로젝트 성능을 악화시키지 않습니다. 소스 코드 시작 부분에 네임 스페이스를 포함 시키면 나쁘지 않습니다. using namespace std지시 사항을 포함시키는 것은 귀하의 필요와 소프트웨어 또는 프로젝트를 개발하는 방식에 따라 다릅니다.

namespace stdC ++ 표준 함수와 변수를 포함합니다. 이 네임 스페이스는 종종 C ++ 표준 함수를 사용할 때 유용합니다.

page 에서 언급 한 바와 같이 :

네임 스페이스 표준을 사용하는 문은 일반적으로 나쁜 습관으로 간주됩니다. 이 명령문의 대안은 유형을 선언 할 때마다 범위 연산자 (: :)를 사용하여 식별자가 속한 네임 스페이스를 지정하는 것입니다.

그리고이 의견을보십시오 :

네임 스페이스를 과도하게 사용할 때 소스 파일에서 "using namespace std"를 사용하면 아무런 문제가 없습니다.

어떤 사람들은 using namespace std네임 스페이스에서 모든 함수와 변수를 호출하기 때문에 소스 파일에 를 포함시키는 것은 나쁜 습관이라고 말했습니다 . 함수에 포함 된 다른 함수와 같은 이름의 새 함수를 정의 namespace std하려면 함수를 오버로드하여 컴파일 또는 실행으로 인해 문제가 발생할 수 있습니다. 예상대로 컴파일되거나 실행되지 않습니다.

page 에서 언급 한 바와 같이 :

std :: std ::는 std 네임 스페이스에 정의 된 클래스 나 유형에 액세스하려고 할 때마다 std 네임 스페이스의 전체를 프로그램의 현재 네임 스페이스로 가져옵니다. 이것이 좋은 일이 아닌 이유를 이해하기 위해 몇 가지 예를 들어 봅시다.

...

이제는 개발의 후반기에 "foo"라는 라이브러리 (예를 들어)에서 구현 된 커스텀의 다른 버전을 사용하기를 원합니다.

...

어떻게 라이브러리가 가리키는 모호성이 있음을 주목하십시오. 컴파일러가이를 감지하고 프로그램을 컴파일하지 않을 수 있습니다. 최악의 경우, 프로그램은 여전히 ​​컴파일 할 수 있지만 잘못된 함수를 호출합니다. 식별자가 속한 네임 스페이스를 지정하지 않았기 때문입니다.


위치에 따라 다릅니다. 일반적인 헤더 인 경우 전역 네임 스페이스에 병합하여 네임 스페이스의 가치를 줄입니다. 이것은 모듈 전역을 만드는 깔끔한 방법 일 수 있습니다.


이것은 종종 글로벌 네임 스페이스 오염이라고하는 나쁜 습관입니다. 두 개 이상의 네임 스페이스가 서명이있는 동일한 함수 이름을 가질 때 문제가 발생할 수 있습니다. 그러면 컴파일러가 어느 것을 호출할지 결정하기가 모호하며 이와 같이 함수 호출과 같이 네임 스페이스를 지정할 때이 모든 것을 피할 수 있습니다 std::cout. 희망이 도움이됩니다. :)





c++-faq