자동으로 C ++ 코드를 이해하기 어렵습니까?


122

나는 모든 C ++ 프로그래머가 사용하도록 장려하는 Herb Sutter의 컨퍼런스를 보았다 auto.

얼마 전에 C # 코드를 읽어야했던 곳 var에서 광범위하게 사용되었으며 코드를 이해하기가 매우 어려웠습니다 var. 잠시 후 변수 유형을 잊어 버렸기 때문에 때로는 두 번 이상!

나는 컴파일러가 유형을 알고 있다는 것을 알고 있으며 그것을 쓸 필요는 없지만 컴파일러가 아닌 프로그래머를 위해 코드를 작성해야한다는 것은 널리 받아 들여지고 있습니다.

또한 작성하기가 더 쉽다는 것도 알고 있습니다.

auto x = GetX();

보다:

someWeirdTemplate<someOtherVeryLongNameType, ...>::someOtherLongType x = GetX();

그러나 이것은 한 번만 작성되며 GetX()반환 유형은 유형 x이 무엇인지 이해하기 위해 여러 번 확인 됩니다.

이 날-않습니다 궁금해했다 auto열심히 C ++ 코드를 이해할 수 있도록?


29
매번 반환 유형을 확인해야 합니까? 코드에서 유형이 명확하지 않은 이유는 무엇입니까? auto함수는 이미 읽기가 어려울 때 (예 : 너무 긴 함수, 이름이 잘못된 변수 등) 일을 읽기가 더 어려워 질 수 있습니다. 적절한 이름의 변수가있는 짧은 함수의 경우 유형이 # 1이 쉽거나 # 2와 관련이 없다는 것을 알면됩니다.
R. Martinho Fernandes

25
사용의 "예술"은 auto언제 사용할 것인지 결정하는 것과 매우 흡사합니다 typedef. 그것이 언제 방해가되고 언제 도움이되는지 결정하는 것은 당신에게 달려 있습니다.
ahenderson

18
나는 같은 문제가 있다고 생각했지만 유형을 몰라도 코드를 이해할 수 있음을 깨달았습니다. 예 : "auto idx = get_index ();" 따라서 idx는 인덱스를 보유한 것입니다. 정확한 유형은 대부분의 경우 관련이 없습니다.
PlasmaHH

31
따라서 글을 쓰지 말고 auto x = GetX();, 특정 상황에서x 실제로 무엇을하는지 알려주는 것보다 더 나은 이름을 선택하십시오 ... 어쨌든 유형보다 더 유용합니다.
Jonathan Wakely

11
더 많은 형식 유추를 사용하여 프로그래머가 코드를 읽기가 어려우면 코드 나 프로그래머가 크게 개선해야합니다.
CA McCann

답변:


99

짧은 대답 : 더 완벽하게, 나의 현재 의견 autoauto명시 적으로 변환을 원하지 않는 한 기본적으로 사용해야한다는 것 입니다. (약간 더 정확하게 말하면, "... 명시 적으로 타입을 커밋하지 않는 한 거의 항상 변환을 원하기 때문입니다.")

더 긴 대답과 근거 :

명시 적으로 형식을 auto커밋하려는 경우에만 명시 적 형식을 작성하십시오. 이는 거의 항상 해당 형식으로의 변환을 명시 적으로 원한다는 것을 의미합니다. 머리 꼭대기에서 나는 두 가지 주요 사례를 회상합니다.

  • (공통) 추론 하는 initializer_list놀라움 . 원하지 않으면 유형을 말하십시오. 즉, 명시 적으로 전환을 요청하십시오.auto x = { 1 };initializer_listinitializer_list
  • (희귀) auto x = matrix1 * matrix 2 + matrix3;프로그래머가 볼 수없는 도우미 또는 프록시 유형 을 캡처하는 등의 표현식 템플릿 사례 . 대부분의 경우 해당 유형을 캡처하는 것이 좋으며 양성이지만 때로는 실제로 유형을 축소하고 계산을 수행하려는 경우 유형을 말하십시오. 즉, 명시 적으로 전환을 요청하십시오.

auto사용 auto하면 함정 을 피하고 코드를 더 정확하고 유지 관리 가능하며 강력하고 효율적으로 만들 수 있으므로 기본적으로 그렇지 않으면 기본적 으로 사용 하십시오. "명확성과 정확성을 위해 먼저 쓰기"의 정신으로, 가장 중요하지 않은 것부터 가장 중요하지 않은 것까지 :

  • 정확성 :auto 보증을 사용 하면 올바른 유형을 얻을 수 있습니다. 그 말대로, 당신이 자신을 반복하면 (예를 들어 유형을 중복하여) 거짓말을 할 수 있고 거짓말 할 것입니다 (잘못합니다). 일반적인 예는 다음과 같습니다 void f( const vector<int>& v ) { for( /*…*.-이 시점에서 반복자 유형을 명시 적으로 작성하는 경우 올바르게 작성하는 것을 기억하고 싶 const_iterator습니까?auto
  • 유지 보수성과 견고성 : 사용은 auto표현의 형태 변경, 때 때문에, 변화의 얼굴에 코드를 더욱 견고하게 auto올바른 유형에 해결하는 것입니다. 대신 명시 적 형식으로 커밋하는 경우 새 형식이 이전 형식으로 변환 될 때 식 형식을 변경하면 자동 변환이 적용되거나 새 형식이 여전히 기존 형식과 비슷하지만 이전 형식으로 변환되지 않으면 불필요한 빌드가 중단됩니다. 예를 들어,를 a map로 변경하면 unordered_map주문에 의존하지 않고 auto반복자를 사용하여 원활하게에서 map<>::iterator로 전환 unordered_map<>::iterator하지만map<>::iterator 어디에서나 인턴이 걸어 다니고 지루한 작업을 방해하지 않는 한 기계적인 코드 수정 리플에서 귀중한 시간을 낭비한다는 의미입니다.
  • 성능 :auto 암시 적 변환이 발생하지 않기 때문에 기본적으로 더 나은 성능을 보장합니다. 대신 유형을 말하고 변환이 필요한 경우 예상대로 변환하지 않는 경우가 종종 있습니다.
  • 사용성 :auto 람다 및 템플릿 도우미와 같이 철자가 어렵고 수정이 불가능한 유형에 대해 반복적 인 decltype표현 에 의존하지 않거나과 같은 비효율적 인 간접 지시를 사용하는 것이 유일 std::function합니다.
  • 편리 성 : 그리고 그렇습니다 auto. 타이핑이 적습니다. 나는 그것을 좋아하는 일반적인 이유이기 때문에 완전성을 위해 마지막으로 언급하지만 그것을 사용하는 가장 큰 이유는 아닙니다.

따라서 auto기본적 으로 말하는 것이 좋습니다. 너무 단순하고 성능이 뛰어나고 명확성이 뛰어나지 않으면 자신과 코드의 미래 관리자에게 상처를 줄뿐입니다. 당신이 그것을 정말로 의미 할 때만 명시적인 타입을 커밋하십시오. 그것은 거의 항상 당신이 명시적인 변환을 원한다는 것을 의미합니다.

예, 이것 에 대한 정보가 있습니다.


14
전환을 원할 때도 자동으로 유용합니다. 다음 유형을 반복하지 않고 명시 적으로 변환을 요청할 수 있습니다 auto x = static_cast<X>(y). 이는 static_cast변환이 의도적임을 명확하게하며 변환에 대한 컴파일러 경고를 피합니다. 일반적으로 컴파일러 경고를 피하는 것이 좋지는 않지만 썼을 때 신중하게 고려한 변환에 대한 경고가 표시되지 않습니다 static_cast. 지금 경고가 없으면이 작업을 수행하지 않지만 잠재적으로 위험한 유형으로 변경되면 나중에 경고를 받고 싶습니다.
Bjarke Hammersholt Roune

6
내가 찾은 것 중 하나 는 특정 구현에 대한 것이 아니라 인터페이스 (OOP 의미가 아닌)에 대해 프로그래밍 auto하려고 노력해야한다는 것 입니다. 템플릿과 동일합니다. 어디에서나 사용되는 템플릿 유형 매개 변수가 있기 때문에 "코드를 읽기 어렵다"고 불평하십니까 ? 아니요, 그렇게 생각하지 않습니다. 템플릿에서도 인터페이스에 대해 코드를 작성하므로 컴파일 타임 덕 타이핑은 많은 사람들이 호출하는 것입니다. T
Xeo

6
"자동 보장을 사용하면 올바른 유형을 얻을 수 있습니다." 전혀 사실이 아닙니다. 코드의 다른 부분에서 규정 한 유형 만 얻을 수 있습니다. 당신이 그것을 숨길 때 그것이 옳은지 아닌지는 완전히 불분명합니다 auto.
궤도에서 가벼움 경주

아무도 IDE에 신경 쓰지 않는다는 것이 정말 놀랍습니다 ... 현대 IDE조차도 auto변수의 경우 클래스 / 구조체 정의로 점프하는 것을 올바르게 지원하지 않지만 거의 모든 것이 명시 적 유형 지정으로 올바르게 수행됩니다. 아무도 IDE를 사용하지 않습니까? 모두 int / float / bool 변수 만 사용합니까? 모두가 자체 문서화 된 헤더 대신 라이브러리에 대한 외부 문서를 선호합니까?
avtomaton

그 gotW : herbsutter.com/2013/08/12/… "initializer_list surprise"가 어떻게 놀라운 지 모르겠습니다 . =RHS 주위의 중괄호 는 다른 해석으로는 의미가 없습니다 (막대 괄호 init-list, 그러나 초기화하는 것을 알아야합니다 auto. 이것은 oxymoron입니다 ). 하나 입니다 놀라운입니다 auto i{1}또한 추론 initializer_list하지 의미에도 불구하고, 이 초기화 목록을 보강 취할 것이 아니라 이 표현을하고 유형을 사용하는 ...하지만 우리가 얻을 수 initializer_list도있다. 고맙게도 C ++ 17은이 모든 것을 잘 해결합니다.
underscore_d

112

상황에 따라 다릅니다.

때로는 코드를 이해하기 어렵게 만들 수도 있습니다. 예를 들어,

void foo(const std::map<int, std::string>& x)
{
   for ( auto it = x.begin() ; it != x.end() ; it++ )
   { 
       //....
   }
}

실제 반복자 선언보다 확실히 이해 하고 작성하기가 쉽습니다.

나는 잠시 동안 C ++을 사용해 왔지만 잊어 const_iterator버렸고 처음에는 iterator... :)

나는 이런 경우에 사용하지만 실제로 상황과 같은 유형을 난독 화하지는 않지만 순전히 주관적입니다.


45
바로 그거죠. 도대체 누가 유형에 관심이 있습니까? 반복자입니다. 나는 타입에 신경 쓰지 않는다. 알아야 할 것은 반복하기 위해 사용할 수 있다는 것 뿐이다.
R. Martinho Fernandes

5
+1. 유형의 이름을 지정 했더라도으로 이름을 지정하므로 이름이 유형에 std::map<int, std::string>::const_iterator대해 많은 것을 알려주는 것처럼 보이지 않습니다.
Steve Jessop

4
@SteveJessop : 적어도 두 가지를 알려줍니다. 키는 int이고 값은 std::string입니다. :)
Nawaz

16
@ Nawaz : it->secondconst 반복자이므로 할당 할 수 없습니다 . 모든 정보는 이전 행의 내용과 반복 const std::map<int, std::string>& x됩니다. 여러 번 말하는 것은 때때로 더 나은 정보를 제공하지만 결코 일반적인 규칙은 아닙니다 :-)
Steve Jessop

11
TBH 나는 for (anX : x)우리가 반복하는 것을 훨씬 더 분명하게 하고 싶습니다 x. 당신이 반복자를 필요로하는 일반적인 경우는 컨테이너를 수정할 때, 그러나 x입니다const&
MSalters

94

다른 방법으로보십시오. 당신은 쓰십니까 :

std::cout << (foo() + bar()) << "\n";

또는:

// it is important to know the types of these values
int f = foo();
size_t b = bar();
size_t total = f + b;

std::cout << total << "\n";

때로는 유형을 명시 적으로 철자하는 데 도움이되지 않습니다.

유형을 언급해야하는지 여부는 중간 변수를 정의하여 여러 명령문으로 코드를 분할할지 여부를 결정하는 것과 다릅니다. C ++ 03에서 두 개는 서로 연결 auto되어 있으므로이를 분리하는 방법으로 생각할 수 있습니다.

때로는 유형을 명시 적으로 만드는 것이 유용 할 수 있습니다.

// seems legit    
if (foo() < bar()) { ... }

vs.

// ah, there's something tricky going on here, a mixed comparison
if ((unsigned int)foo() < bar()) { ... }

변수를 선언하는 경우를 사용 auto하면 여러 표현식에서와 마찬가지로 유형을 무언으로 표시 할 수 있습니다. 가독성에 도움이되고 방해가되는시기를 스스로 결정해야합니다.

부호있는 유형과 부호없는 유형을 혼합하는 것은 처음에는 실수라고 주장 할 수 있습니다 (사실, 일부는 서명되지 않은 유형을 전혀 사용하지 않아야한다고 주장합니다). 이유 는 틀림없이 실수는 있기 때문에 다른 행동의 피연산자의 유형이 매우 중요하게한다는 것입니다. 값의 유형을 알아야하는 것이 좋지 않은 경우에는 값을 알 필요가없는 것도 좋지 않습니다. 따라서 코드가 다른 이유로 혼란스럽지 않으면 auto괜찮습니다. ;-)

특히 일반 코드를 작성할 때 실제 유형의 변수 중요 하지 않은 경우가 있습니다. 중요한 것은 필요한 인터페이스를 충족시키는 것입니다. 따라서 auto유형을 무시하는 추상화 수준을 제공합니다 (물론 컴파일러는 그렇지 않습니다). 적절한 수준의 추상화에서 작업하면 가독성이 상당히 높아질 수 있으며 "잘못된"수준에서 작업하면 코드를 느슨하게 읽을 수 있습니다.


21
+1을 auto사용하면 이름이 없거나 흥미롭지 않은 유형의 이름이 지정된 변수를 만들 수 있습니다. 의미있는 이름이 유용 할 수 있습니다.
Mankarse

부호없는 것과 부호없는 것을 적절히 사용하기 위해 부호없는 것을 사용하는 경우 : 모듈 식 산술. 양의 정수에 대해 부호없는 것을 오용하는 것이 아닙니다. 서명되지 않은 프로그램은 거의 사용되지 않지만 핵심 언어 sizeof는 서명되지 않은 것으로 정의 되지 않습니다.
curiousguy

27

IMO, 당신은 이것을 거의 반대로보고 있습니다.

auto읽을 수 없거나 읽기 어려운 코드 로 이어지는 것은 중요하지 않습니다 . 반환 값에 대한 명시 적 유형을 갖는 것은 (특정) 특정 함수에 의해 반환되는 유형이 분명하지 않다는 사실을 보완합니다.

적어도 내 견해로는, 반환 유형이 즉시 명확하지 않은 함수가 있다면 바로 그게 문제입니다. 함수의 기능은 이름에서 분명해야하며 반환 값의 유형은 기능에서 분명해야합니다. 그렇지 않다면 이것이 문제의 실제 원인입니다.

여기에 문제가 있으면와 관련이 없습니다 auto. 코드의 나머지 부분과 함께 있으며 명시 적 유형이 핵심 문제를 보거나 수정하지 못하도록 반창고로 충분할 가능성이 매우 높습니다. 그 실제 문제를 해결 auto하면 일반적으로 사용하는 코드의 가독성이 좋습니다.

나는 공평하게 추가해야한다고 가정합니다. 나는 그런 것들이 당신이 원하는 것만 큼 거의 명확하지 않은 몇 가지 경우를 다루었 고, 문제를 해결하는 것도 상당히 불가능합니다. 예를 들어, 몇 년 전에 다른 회사와 합병 한 회사에 대한 컨설팅을 수행했습니다. 그들은 실제로 합쳐진 것보다 "함께 뭉쳐진"코드베이스로 끝났다. 구성 프로그램은 비슷한 목적으로 서로 다른 (그러나 매우 유사한) 라이브러리를 사용하기 시작했으며 더 깨끗하게 병합하기 위해 노력했지만 여전히 그랬습니다. 상당히 많은 경우에, 주어진 함수에 의해 어떤 타입이 리턴 될지 추측하는 유일한 방법은 그 함수가 어디서 시작되었는지 아는 것입니다.

이 경우에도 몇 가지 사항을 더 명확하게 만들 수 있습니다. 이 경우 모든 코드가 전역 네임 스페이스에서 시작되었습니다. 일부 네임 스페이스로 상당히 많은 양을 옮기면 이름 충돌이 없어지고 형식 추적도 상당히 쉬워졌습니다.


17

일반적인 용도로 자동차를 싫어하는 데는 몇 가지 이유가 있습니다.

  1. 코드를 수정하지 않고 리팩토링 할 수 있습니다. 예, 이것은 종종 자동 사용의 이점으로 열거 된 것 중 하나입니다. 함수의 반환 유형을 변경하기 만하면 호출하는 모든 코드가 자동을 사용하면 추가 노력이 필요하지 않습니다! 컴파일하고, 0 경고, 0 오류를 빌드하면 함수가 사용되는 80 곳을 살펴보고 잠재적으로 수정하는 혼란을 처리하지 않고도 코드를 체크인 할 수 있습니다.

하지만 잠깐, 정말 좋은 생각입니까? 이 유스 케이스의 수십 개에서 유형이 중요하고 이제 해당 코드가 실제로 다르게 작동하면 어떻게 될까요? 또한 입력 값뿐만 아니라 함수를 호출하는 다른 클래스의 개인 구현 동작 자체를 수정하여 캡슐화를 암시 적으로 중단 할 수 있습니다.

1a. 나는 "자체 문서화 코드"의 개념을 믿는 사람입니다. 자체 문서화 코드의 이유는 주석이 최신이 아니며 코드가 수행하는 작업을 더 이상 반영하지 않는 반면, 코드 자체는 명시적인 방식으로 작성된 경우 자체 설명이 필요하기 때문에 항상 최신 상태를 유지한다는 것입니다. 의도에 따라 부실한 의견과 혼동하지 마십시오. 코드 자체를 수정하지 않고 유형을 변경할 수 있으면 코드 / 변수 자체가 오래 될 수 있습니다. 예를 들면 다음과 같습니다.

자동 bThreadOK = CheckThreadHealth ();

문제는 어떤 시점에서 CheckThreadHealth ()가 리팩터링되어 부울 대신 오류 상태를 나타내는 열거 형 값을 반환한다는 것입니다. 그러나 그 변경을 한 사람은이 특정 코드 줄을 검사하는 것을 놓쳤으며 컴파일러는 경고 나 오류없이 컴파일했기 때문에 도움이되지 않았습니다.

  1. 실제 유형이 무엇인지 모를 수도 있습니다. 이것은 종종 자동차의 주요 "혜택"으로 표시됩니다. "누가 신경 쓰는가? 컴파일"이라고 말할 수있을 때 함수가 무엇을 제공하는지 배우십시오.

아마 일종의 작품 일 것입니다. 루프 반복마다 500 바이트 구조체를 복사하더라도 단일 값을 검사 할 수 있기 때문에 코드는 여전히 완벽하게 작동하기 때문에 일종의 작업이 필요합니다. 따라서 단위 테스트조차도 잘못된 코드가 단순하고 순진한 자동차 뒤에 숨어 있음을 깨닫는 데 도움이되지 않습니다. 대부분의 다른 사람들이 파일을 스캔하면 언뜻보기에도 파일을 알 수 없습니다.

유형이 무엇인지 모르는 경우 유형이 무엇인지에 대해 잘못된 가정을하는 변수 이름을 선택하면 실제로 1a에서와 동일한 결과를 얻을 수 있지만 처음부터 시작하는 것보다 오히려 악화 될 수 있습니다 사후 리 팩터.

  1. 코드를 처음 작성할 때 코드를 입력하는 것은 프로그래밍에 가장 많은 시간이 걸리지 않습니다. 예, auto는 처음에 일부 코드를 더 빨리 작성합니다. 면책 조항으로 100 WPM 이상을 입력하므로 다른 사람들만큼 귀찮게하지 않을 수도 있습니다. 그러나 하루 종일 새 코드를 작성하는 것만으로도 행복한 캠프가 될 것입니다. 프로그래밍에서 가장 시간이 많이 걸리는 부분은 코드에서 재현하기 어려운 엣지 케이스 버그를 진단하는 것인데, 종종 자동차의 과잉 사용이 발생할 수있는 미묘한 문제가 발생하는 경우가 많습니다 (참조 대 복사, 부호 vs. 부호 없음, float vs. int, bool vs. 포인터 등).

auto는 기본적으로 표준 라이브러리 템플릿 유형의 끔찍한 구문에 대한 해결 방법으로 소개 된 것 같습니다. 사람들이 이미 잘 알고있는 템플릿 구문을 고치려고하지 말고 기존 코드로 인해 거의 불가능할 수도 있습니다. 기본적으로 문제를 숨기는 키워드를 추가하십시오. 본질적으로 "핵심"이라고 부르는 것.

실제로 표준 라이브러리 컨테이너와 함께 auto를 사용하는 것에 동의하지 않습니다. 분명히 키워드가 만들어졌으며 표준 라이브러리의 기능이 근본적으로 목적 (또는 그 유형에 대한 유형)이 변경되지 않아서 자동차를 비교적 안전하게 사용할 수 있습니다. 그러나 나는 훨씬 더 휘발성이 있고 잠재적으로 더 근본적인 변화를 겪을 수있는 자신의 코드와 인터페이스와 함께 사용하는 것에 매우 신중할 것입니다.

언어의 기능을 향상시키는 또 다른 유용한 자동 응용 프로그램은 유형에 관계없이 매크로로 임시를 만드는 것입니다. 이것은 전에는 할 수 없었지만 지금 할 수 있습니다.


4
니가 끝냈어. 이 +2를 줄 수 있으면 좋겠다.
cmaster

좋은 "조심해야한다"라는 대답. @ cmaster : 있습니다.
중복 제거기

유용한 사례가 하나 더 발견되었습니다 auto something = std::make_shared<TypeWithLongName<SomeParam>>(a,b,c);. :-)
Notinlist

14

예,를 사용하지 않으면 변수 유형을 더 쉽게 알 수 있습니다 auto. 질문 : 당신이 할 필요가 코드를 읽을 수 있도록 변수의 유형을 알고? 때때로 대답은 '예', '아니요'입니다. 예를 들어,에서 반복자를 가져올 때 std::vector<int>그것이 충분 std::vector<int>::iterator하거나 auto iterator = ...;충분 하다는 것을 알아야 합니까? 반복자와 관련하여 원하는 모든 것은 반복 자라는 사실에 의해 제공됩니다. 유형이 무엇인지는 중요하지 않습니다.

auto코드를 읽기 어렵게 만들지 않는 상황에서 사용하십시오 .


12

개인적으로 나는 auto그것이 프로그래머에게 그것이 분명한 경우에만 사용 합니다.

실시 예 1

std::map <KeyClass, ValueClass> m;
// ...
auto I = m.find (something); // OK, find returns an iterator, everyone knows that

실시 예 2

MyClass myObj;
auto ret = myObj.FindRecord (something)// NOT OK, everyone needs to go and check what FindRecord returns

5
이것은 가명을 손상시키는 가독성이 좋지 않은 실제 사례입니다. 아무도 "DoSomethingWeird"가하는 일에 대한 가장 확실한 아이디어를 가지고 있지 않기 때문에 auto를 사용하거나 더 사용하지 않아도 읽을 수 없게됩니다. 어느 쪽이든 문서를 확인해야합니다.
R. Martinho Fernandes

4
좋아, 지금은 좀 나아 졌어. 그래도 변수 이름이 잘못되어 여전히 아프다는 것을 알았습니다. 당신이 쓸 수 있었 auto record = myObj.FindRecord(something)이 변수 유형을 기록했다 분명하다. it또는 이와 비슷한 이름을 지정 하면 반복자를 반환한다는 것이 분명해집니다. 사용하지 않더라도 auto변수의 이름을 올바르게 지정 하면 함수의 어느 곳에서나 유형을보기 위해 선언으로 건너 뛸 필요가 없습니다 . 예제가 지금 완전한 밀짚 꾼이 ​​아니기 때문에 다운 보트를 제거했지만 여전히 여기서 논쟁을 사지 않습니다.
R. Martinho Fernandes

2
@ R.MartinhoFernandes에 추가하려면 : "기록"이 정확히 무엇입니까? 그것은 내가이 기록되는 것을 더 중요하게 생각하고, 실제 기본 원시 형은 .. 또 다른 추상화 계층이다 그래서 사람은 자동차없이 아마 할 것이다 :MyClass::RecordTy record = myObj.FindRecord (something)
paul23

2
@ paul23 : 자동 대 유형을 사용하면 얻는 것이 무엇이고, 유일한 반대 의견이 "사용 방법을 모른다"는 것입니다. 어쨌든 당신이 그것을 찾게합니다.
GManNickG 2014

3
@GManNickG 그것은 중요하지 않은 유형의 정확한 유형을 알려줍니다.
paul23

10

이 질문은 의견을 요구하는데, 이는 프로그래머마다 다를 수 있지만, 아니오라고 말할 것입니다. 실제로 많은 경우에 반대의 경우 auto, 프로그래머가 간단한 것이 아니라 논리 에 집중할 수있게하여 코드를 이해하기 쉽게 만들 수 있습니다 .

복잡한 템플릿 유형의 경우 특히 그렇습니다. 다음은 단순화되고 고안된 예입니다. 어느 것이 더 이해하기 쉬운가요?

for( std::map<std::pair<Foo,Bar>, std::pair<Baz, Bot>, std::less<BazBot>>::const_iterator it = things_.begin(); it != things_.end(); ++it )

.. 또는 ...

for( auto it = things_.begin(); it != things_.end(); ++it )

어떤 사람들은 두 번째가 이해하기 쉽다고 말하고 다른 사람들은 첫 번째 말을 할 수도 있습니다. 그러나 다른 사람들은 무의미한 사용이 auto그것을 사용하는 프로그래머의 멍청한 짓에 기여할 수 있다고 말하지만 , 그것은 또 다른 이야기입니다.


4
+1 Haha, 모든 사람이 std::map예제를 제시 하고 복잡한 템플릿 인수도 추가했습니다.
Nawaz

1
@ Nawaz : maps를 사용하여 미친 이름 의 템플릿 이름을 쉽게 만들 수 있습니다 . :)
John Dibling

@Nawaz : 그러나 왜 아무도 더 나은 읽기 쉬운 대안으로 루프 기반의 범위를 가지지 않을지 궁금합니다.
PlasmaHH

1
@PlasmaHH, 반복자가있는 모든 루프가 범위 기반으로 대체 될 수있는 것은 아닙니다 ( for예 : 반복자가 루프 본문에서 무효화되어 사전 증분되거나 증분되지 않아야하는 경우).
Jonathan Wakely

@ PlasmaHH : 제 경우에는 MSVC10이 범위 기반 for 루프를 수행하지 않습니다. MSVC10은 C ++ 11 테스트 베드이므로 실제로 경험이 많지 않습니다.
John

8

지금까지 많은 좋은 대답이 있었지만 원래 질문에 집중하기 위해 Herb는 그의 조언에서 너무 멀리 auto나가서 자유롭게 사용하기를 원한다고 생각합니다. 귀하의 예는 사용 auto이 가독성 을 분명히 손상시키는 경우 입니다. 어떤 사람들은 변수 위에 마우스를 올려 놓고 유형을 볼 수있는 최신 IDE에서는 문제가 아니라고 주장하지만 동의하지 않습니다. 항상 IDE를 사용하는 사람들조차 때때로 코드 조각을 독립적으로 봐야합니다 (코드 검토 생각) 예를 들어) IDE는 도움이되지 않습니다.

결론 : auto그것이 도움이 될 때 사용 하십시오 : 예를 들어 반복문의 반복자. 독자가 유형을 찾기가 어려울 때 사용하지 마십시오.


6

명확한 유형이 없으면 아무도 자동으로 지적하지 않는다는 것이 놀랍습니다. 이 경우 템플릿에서 #define 또는 typedef를 사용하여 실제 사용 가능한 유형을 찾고 (때로는 사소하지 않음)이 문제를 해결하거나 auto를 사용하면됩니다.

플랫폼 별 유형으로 무언가를 반환하는 함수가 있다고 가정하십시오.

#ifdef PLATFROM1
__int256 getStuff();
#else //PLATFORM2
__int128 getStuff();
#endif

마녀 사용법을 원하십니까?

#ifdef PLATFORM1
__int256 stuff = getStuff();
#else
__int128 stuff = getStuff();
#endif

아니면 그냥

auto stuff = getStuff();

물론 쓸 수 있습니다

#define StuffType (...)

어딘가에 있지만

StuffType stuff = getStuff();

실제로 x의 타입에 대해 더 많은 것을 말하고 있습니까? 그것은 거기에서 반환되는 것을 알려주지 만 정확히 자동차입니다. 이것은 '중복'입니다- '물건'은 여기에서 3 번 작성됩니다. 이것은 내 의견으로는 '자동'버전보다 읽기가 어렵습니다.


5
플랫폼 별 유형을 처리하는 올바른 방법은 해당 유형입니다 typedef.
cmaster

3

가독성은 주관적입니다. 상황을보고 가장 좋은 것을 결정해야합니다.

당신이 지적했듯이, 자동없이 긴 선언은 많은 혼란을 일으킬 수 있습니다. 그러나 지적했듯이 짧은 선언으로 인해 가치가있는 유형 정보가 제거 될 수 있습니다.

이 외에도, 나는 이것을 추가 할 것입니다 : 당신이 가독성이 아닌 가독성을보고 있는지 확인하십시오. 작성하기 쉬운 코드는 일반적으로 읽기 쉽지 않으며 그 반대도 마찬가지입니다. 예를 들어, 글을 쓰고 있다면 자동차를 선호합니다. 내가 읽고 있다면 아마도 더 긴 선언 일 것입니다.

그런 다음 일관성이 있습니다. 그게 얼마나 중요합니까? 어떤 부분에서는 자동으로, 다른 부분에서는 명시 적으로 선언하거나 전체적으로 일관된 방법을 원하십니까?


2

읽을 수없는 코드를 장점으로 삼아 프로그래머가 더 많이 사용하도록 장려 할 것입니다. 왜? auto를 사용하는 코드를 읽기가 어렵다면 분명히 쓰기도 어렵습니다. 프로그래머는 자신의 작업을 개선하기 위해 의미있는 변수 이름을 사용해야합니다 .
처음에는 프로그래머가 의미있는 변수 이름을 쓰지 않을 수 있습니다. 그러나 결국 버그를 수정하거나 코드를 검토하는 동안 다른 사람에게 코드를 설명해야하거나 가까운 시일 내에 유지 보수 담당자에게 코드를 설명해야 할 때 프로그래머는 실수를 깨닫고 사용할 것입니다. 미래에 의미있는 변수 이름.


2
기껏해야 변수 myComplexDerivedType유형을 작성하는 사람들 이 누락 된 유형을 구성하게하여 유형 반복 (변수가 사용되는 모든 위치)에 의해 코드가 복잡해지고 사람들 이 이름에서 변수 의 목적 을 생략하도록 유도합니다 . 제 경험은 코드에 적극적으로 장애물을 두는 것만 큼 비생산적인 것이 없다는 것입니다.
cmaster

2

두 가지 지침이 있습니다.

  • 변수의 유형이 명백한 경우, 자동 사용을 결정하기가 어렵거나 지루합니다.

    auto range = 10.0f; // Obvious
    
    for (auto i = collection.cbegin(); i != cbegin(); ++i) // Tedious if collection type
    // is really long
    
    template <typename T> ... T t; auto result = t.get(); // Hard to determine as get()
    // might return various stuff
  • 특정 변환이 필요하거나 결과 유형이 명확하지 않아 혼동 될 수 있습니다.

    class B : A {}; A* foo = new B(); // 'Convert'
    
    class Factory { public: int foo(); float bar(); }; int f = foo(); // Not obvious

0

예. 자세한 내용은 줄이지 만 일반적인 오해는 자세한 내용은 가독성을 줄인다는 것입니다. 가독성을 코드를 실제로 해석 할 수있는 능력이 아니라 미학적으로 간주하는 경우에만 해당됩니다. 이는 자동을 사용하여 증가시키지 않습니다. 가장 일반적으로 인용되는 예인 벡터 반복기에서는 자동을 사용하면 코드의 가독성이 향상되는 것처럼 보일 수 있습니다. 반면에 자동 키워드가 무엇을 줄지 항상 알 수있는 것은 아닙니다. 내부 재구성을 수행하기 위해 컴파일러와 동일한 논리 경로를 따라야하며, 특히 반복자와 관련하여 많은 시간이 걸리면 잘못된 가정을해야합니다.

하루가 끝날 무렵 '자동'은 구문 및 미학적 '청결성'(반복자가 구문을 불필요하게 복잡하게 만들었을 때만 필요함)과 주어진 행에 10 자 미만의 문자를 입력 할 수있는 능력을 위해 코드의 가독성과 선명도를 희생합니다. 위험이나 장기적인 노력에 가치가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.