루프에서 새로운 C ++ 11 '자동'기능을 사용해야합니까?


20

auto특히 for 루프에서 키워드 를 사용할 때의 장단점은 무엇입니까 ?

for(std::vector<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->something();
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); it++ )
{
   it->second->something();
}

for(auto it = x.begin(); it != x.end(); it++ )
{
   it->??
}

당신이지도 또는 당신이 모르는 것 벡터에 대한 반복자를 가지고 있는지 모르는 경우처럼 보인다 사용 여부를 first하거나 second또는 개체의 바로 직접 액세스 속성, 아니?

키워드 사용 여부에 대한 C # 토론을 생각 나게합니다 var. 내가 지금 얻는 인상은 C ++ 세계에서 사람들이 C # 세계 auto보다 싸울 필요없이 키워드 를 채택 할 준비가되어 있다는 것 var입니다. 저에게 제 첫 번째 본능은 변수의 유형을 알고 싶어서 어떤 연산을 수행 할 수 있는지 알 수 있다는 것입니다.


3
기다림! 사용 여부에 대한 싸움이 있었 var습니까? 나는 그것을 놓쳤다.
pdr

21
더 좋은 방법은, 그냥 사용할 수도 있습니다 for (auto& it : x)(또는 복사를 원한다면 참조없이)
Tamás Szelei

7
내용을 반복하기 위해 루프를 작성하고 있으며 내용이 x무엇인지조차 모르는 x경우 처음에 해당 루프를 작성해서는 안됩니다. ;-)
nikie

@fish : 범위 기반 for-loops 규칙이지만, 자동을 사용한다고 생각할 때 범위 기반 for-loops를 사용할 때 'for (T & it : x)'와 같이 비판적이며 끝났을 것입니다. 내 마음에 자동차를 오용하는 것.
martiert

var를 사용하는 것에 대한 싸움은 조금 어리 석었습니다. 특히 회고하십시오. 카고 컬트 프로그래밍을 참조하십시오 .
Craig

답변:


38

메타 프로그래밍 및 기타 사항으로 인해 유형이 C # 유형보다 훨씬 복잡하고 복잡해질 수 있으므로 C ++의 동기는 더 극단적입니다. auto명시 적 유형보다 쓰기 및 읽기 속도가 빠르고 유연하고 유지 관리가 가능합니다. 내 말은, 타이핑을 시작하고 싶니?

boost::multi_map<NodeType, indexed_by<ordered_unique<identity<NodeType>>, hashed_non_unique<identity<NodeType>, custom_hasher>>::iterator_type<0> it

그것은 완전한 유형조차 아닙니다. 몇 가지 템플릿 인수를 놓쳤습니다.


8
예를 들어 +1이지만 "modern"C ++의 상태에 대해서도 알려줍니다.
zvrba

22
@zvrba : 예. 일반적인 기능은 C #보다 훨씬 강력합니다.
DeadMG

4
형식 정의가 무엇의 그
gbjbaanb

19
@gbjbaanb 아니, 그게 다야 auto. 디자인에 의해. typedef도움이되지만 auto더 도움이됩니다.
Konrad Rudolph

1
typedef는 "자동으로 긴 타입을 만들지 않는다"는 주장을 무효화합니다
Michael

28

귀하의 예에서 :

for(auto it = x.begin(); it != x.end(); i++)
{
  it->??
}

x보이는 선언이 있어야합니다 . 따라서 유형 it이 분명해야합니다. 유형이 x명확하지 않으면 메서드가 너무 길거나 클래스가 너무 큽니다.


7
또한 x컨테이너에 매우 나쁜 변수 이름입니다. 경우에 따라 (의미 적으로 가치있는) 이름을보고 가능한 작업을 유추 할 수 있습니다.
Max

@ Max : x일반적인 예제 로만 사용 되며 설명적인 변수 이름을 사용하는 경향이 있습니다.
사용자

@User 물론, 나는 이것이 실제 사례라고 생각하지는 않았다;)
Max

14

이의 제기 ! 로드 된 질문입니다.

세 번째 코드가 왜 포함되어 있는지 설명 할 수 있습니까 ???하지만 첫 번째와 두 번째 코드는 그렇지 않습니다. 공정성을 위해 코드 다음과 같이 읽어야합니다.

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->???
}

for(std::map<T>::iterator it = x.begin(); it != x.end(); i++)
{
   it->second->???
}

그곳에. 를 사용하지 않아도 동일한 문제가 발생합니다 auto.

그리고 모든 경우에 대한 답은 동일합니다 : 상황이 중요 합니다. 독립적으로 코드 조각에 대해 의미있게 이야기 할 수는 없습니다. 템플릿을 사용하지 않고 구체적인 유형을 사용하더라도 코드 독자는 해당 유형의 선언에 대해 알아야하기 때문에 문제를 다른 곳으로 이동했을 것입니다.

사용하는 경우 auto이러한 상황에서이 코드를 렌더링 당신은 당신의 코드 디자인 뭔가 잘못이 있다는 경고 표시로이 문제를 처리해야 읽을. 물론, 비트 연산이나 레거시 API를 처리 할 때와 같이 하위 수준의 세부 정보가 중요한 경우에는 명시 적 형식이 가독성에 도움이 될 수 있습니다. 그러나 일반적으로 – 아니요.

에 대해서는 var(명시 적으로 언급 이후)하는도의 광대 한 합의 는 C # 커뮤니티 에 대한 사용은 var. 그것의 사용에 반대하는 주장은 일반적으로 오류에 기초한다 .


1
난 당신이 옆에 두는 것이 무엇인지 잘 모릅니다 자동으로 포인트가 생각 ... 그것은 "뭔가"코드 고유의 것입니다 아니면 "무언가를"방법을 가지고 데이터 객체에 도착 풀고 관련 데이터 형입니다
마이클

1
다른 두 코드에 당신은 : @Ptolemy 그리고 내 요점은 또한 (일반적으로) 다음에 무엇을 입력해야되는지 모르겠어요 T으로 사용자에게 불투명하다 auto. 그러나 하나는 괜찮고 다른 하나는 그렇지 않습니까?! 말이되지 않습니다. OP의 경우 T임의 유형에 대한 스탠드 인입니다. 실제 코드에서는 템플릿 (for typename std::vector<T>::iterator…)이나 클래스 인터페이스를 사용할 수 있습니다 . 두 경우 모두 실제 유형은 사용자에게 숨겨져 있지만 일상적으로 이러한 코드를 문제없이 작성합니다.
Konrad Rudolph

1
실제로 그렇습니다. 그것의 벡터라면, 당신은 당신이해야 할 것을 알고 있습니다-> 그리고 당신은 당신의 데이터 유형에 액세스 할 수 있습니다. 맵인 경우,-> 두 번째-> 수행해야한다는 것을 알고 데이터 유형에 액세스 할 수 있습니다 (자동 인 경우 데이터 유형에 액세스하기 위해 무엇을해야하는지 알 수 없음). "STL 콜렉션에 포함 된 데이터 유형은 무엇입니까"와 "어떤 STL 콜렉션 유형이 있습니까?"를 혼동하는 것 같습니다. auto는이 문제를 악화시킵니다.
Michael Shaw

1
@Ptolemy이 인수는 모두 사용할 때와 동일합니다 auto. x컨텍스트에서 어떤 작업이 지원 되는지 확인하는 것은 쉽지 않습니다 . 실제로이 유형은 추가 정보를 제공 하지 않습니다 . 두 경우 모두 지원되는 작업 세트를 알려주는 보조 (IDE, 문서, 지식 / 메모리)가 필요합니다.
Konrad Rudolph

1
즉 @Ptolemy 단지 당신이 알고하지 않는 것이 매우 뒤얽힌 상황에있는 경우에 true를 begin반환하지만 않는 것을 알고 std::vector<>::iterator있다. 그리고이 정보를 간단하게 제공 할 수없는 나쁜 프로그래밍 도구를 사용해야합니다. 이것은 매우 복잡합니다. 실제로, 당신도 모두 알고 beginiterator또는 둘 다, 당신은 쉽게 당신에게 관련 정보를 제공 할 수있는 IDE 또는 편집기를 사용한다. 모든 최신 IDE 및 프로그래밍 편집기가이를 수행 할 수 있습니다.
Konrad Rudolph

11

찬성

귀하의 코드 :

for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

템플릿 종속 이름으로 인해 컴파일되지 않습니다.

이것은 올바른 구문입니다.

for( typename std::vector<T>::iterator it = x.begin(); it != x.end(); i++)

이제 타입 선언의 길이를 살펴보십시오. auto키워드가 소개 된 이유를 알려줍니다 . 이 :

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

더 간결합니다. 그래서 이것은 전문가입니다.


범죄자

약간 조심해야합니다. 키워드를 사용 auto하면 선언 한 유형을 얻습니다.

예를 들면 다음과 같습니다.

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto it : v )
{
  ++ it;   // ops modifying copies of vector's elements
}

vs

std::vector< int > v{ 1, 2, 3, 4 };
for ( auto & it : v )   // mind the reference
{
  ++ it;   // ok, vector's elements modified
}

결론 : 예, 사용해야하지만 과용해서는 안됩니다. 어떤 사람들은 그것을 너무 많이 사용하는 경향이 있으며 다음 예와 같이 어디서나 자동차를 사용합니다.

auto i = 0;

vs

int i = 0;

auto i = 0. 저지른. 나는 그렇게한다. 그러나 그것이 0유형의 리터럴 이라는 것을 알고 있기 때문 int입니다. (및 8 진 상수 ;-))
Laurent LA RIZZA

6

예, 당신은해야합니다! auto유형을 지우지 않습니다. "알지 못하는"경우에도 x.begin()컴파일러는 형식을 잘못 사용하면 오류를 알고보고합니다. 또한를 map사용 하여 에뮬레이트 하는 것은 드문 일이 아니므로 vector<pair<Key,Value>>사용하는 코드 auto가 두 사전 표현 모두에서 작동합니다.


4

예, auto기본 규칙으로 사용해야합니다 . 명시 적으로 유형을 지정하는 것보다 원시 이점이 있습니다.

  • 컴파일러가 이미 알고있는 것을 입력하지는 않습니다.
  • 변수 유형이 리턴 값 유형의 변경 사항을 "따라"따라갑니다.
  • 이렇게하면 로컬 변수 초기화에서 암시 적 변환 및 슬라이싱이 자동으로 발생하지 않습니다.
  • 템플릿에서 명시 적 유형 계산이 필요하지 않습니다.
  • 긴 이름을 가진 리턴 유형의 이름을 지정할 필요가 없습니다. (컴파일러 진단에서 복사하여 붙여 넣는 것)

이곳에서 선택하실 수 있습니다. 선택의 여지가없는 경우도 있습니다 :

  • 람다 유형과 같이 처리 할 수없는 유형의 변수를 선언 할 수 있습니다.

정확히 무엇을 알고 auto있다면 단점이 없습니다.

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