문제

다음 중 어느 것이 더 좋고 그 이유는 무엇입니까? (특히 C ++)

ㅏ.

int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

비.

for( int i(0);i < vec.length(); ++i)
{
  //loop body
}

길이 기능을 호출하기 때문에 (a)에 대한 조언을 보았습니다. 이것은 나를 괴롭 히고 있습니다. 현대 컴파일러가 (b)의 최적화가 (a)와 비슷하지 않습니까?

도움이 되었습니까?

해결책

예 (b)는 예제 (a)와 다른 의미를 가지며 컴파일러는 당신이 그것을 쓸 때 그것을 해석해야합니다.

만약 (내가 생각할 수없는 몇 가지 구성된 이유로), 나는 이것을하기 위해 코드를 썼다.

for( int i(0);i < vec.length(); ++i)
{
    if(i%4 == 0)
       vec.push_back(Widget());
}

다른 결과를 얻을 수 있기 때문에 컴파일러가 Vec.length ()로 각 호출을 최적화하기를 원하지 않았을 것입니다.

다른 팁

좋아요:

for (int i = 0, e = vec.length(); i != e; ++i)

물론 이것은 반복자에게도 효과가 있습니다.

for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)

둘 다 효율적이기 때문에 이것을 좋아합니다 (전화 end() 한 번만), 또한 상대적으로 간결한 (유형이 필요하지 않습니다. vector<int>::const_iterator 한 번).

아무도 명백한 말을하지 않았다는 것에 놀랐습니다.

99.99%의 경우에는 중요하지 않습니다.

계산하는 컨테이너를 사용하지 않는 한 size() 고가의 운영이며, 프로그램이 몇 나노초가 느리게 진행되는 것은 헤아릴 수 없습니다. 코드를 프로필하고 size() 병목 현상입니다.

여기에는 토론해야 할 두 가지 문제가 있습니다.

  1. 변수 범위
  2. 최종 조건 재평가

가변 범위

일반적으로 루프 외부에서 루프 변수가 표시되지 않아도됩니다. 그래서 당신이 그것을 내부에서 선언 할 수있는 이유입니다 for 건설하다.

최종 조건 재평가

Andrew Shepherd는 그것을 멋지게 말했습니다. 그것은 최종 조건 내에 기능 호출을 넣는 데 다른 것을 의미합니다.

for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
   if( ... ) v.push_back( i ); // contrived, but possible
}

// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}

왜 당신을 몸에 담그고 있습니까? 이 두 가지 대안은 똑같이하는 것을 보지 못합니다. 하나는 고정 된 수의 반복을 수행하는 반면, 다른 하나는 루프 본체에 의존합니다.

또 다른 대안 Colud는

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

루프 외부의 루프 변수가 필요하지 않으면 두 번째 접근 방식이 바람직합니다.

반복자는 실제로 당신에게 좋은 또는 더 나은 성능을 제공합니다. (comp.lang.c ++에는 큰 비교 스레드가있었습니다.

또한 나는 사용할 것입니다

int i = 0;

당신이 사용하고있는 구문과 같은 생성자 대신. 유효하지만 관용적이지 않습니다.

다소 관련이없는 :

경고 : 서명 된 정수와 서명되지 않은 정수의 비교.

배열 및 벡터 지수의 올바른 유형은 다음과 같습니다 size_t.

엄격하게 말하자면, C ++에서는 짝수입니다 std::vector<>::size_type.

얼마나 많은 C/C ++ 개발자가 여전히 이것을 잘못했는지 놀랍습니다.

생성 된 코드를 보자 (나는 최적화로 MSVS 2008을 사용한다).

ㅏ.

int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

For 루프는 2 개의 어셈블러 지침을 생성합니다.

비.

for( int i(0);i < vec.size(); ++i)
{
  //loop body
}

For 루프는 8 개의 어셈블러 지침을 생성합니다. Vec.size ()가 성공적으로 상환됩니다.

씨.

for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
  //loop body
}

For 루프는 15 개의 어셈블러 지침을 생성합니다 (모든 것이 감소하지만 코드에는 많은 점프가 있습니다).

따라서 애플리케이션이 성능이 중요하다면 a). 그렇지 않으면 b) 또는 c).

반복자 예제는 다음과 같습니다.

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

루프 반복기 ''루프 본체가 벡터가 재 할당을 유발 해야하는 경우 'IT'를 무효화 할 수 있습니다. 따라서 그것은 동일하지 않습니다

for (int i=0;i<vec.size();++i){
 //loop body
}

루프 바디가 Vec에 요소를 추가하는 곳.

간단한 질문 : 수정하고 있습니다 vec 루프에서?

이 질문에 대한 답변은 귀하의 답변으로 이어질 것입니다.

JRH

컴파일러가 들어 오기가 매우 어렵습니다. vec.length() 안전한 지식이 상감되지 않는 한 안전한 지식을 부르십시오. 하지만 적어도 i 두 번째 스타일 "B"로 명확하게 선언해야합니다. length 호출은 루프에서 "수동으로"올라 가야합니다!

이것은 바람직하다 :

typedef vector<int> container; // not really required,
                               // you could just use vector<int> in for loop

for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
    // do something with (*i)
}
  • 벡터가 업데이트되지 않는다고 즉시 알 수 있습니다.
  • 누구나 여기서 무슨 일이 일어나고 있는지 알 수 있습니다
  • 나는 얼마나 많은 루프를 알고 있습니다
  • v.end() 마지막 요소를 지나서 포인터를 반환하므로 크기 확인의 오버 헤드가 없습니다.
  • 다른 컨테이너 또는 값 유형에 대해 쉽게 업데이트 할 수 있습니다

(b) 매번 함수를 계산/호출하지 않습니다.

-발췌 ----

루프 불변 코드 모션 : GCC에는 루프 최적화 제조업체의 일부로 루프 불일치 코드 모션이 포함되어 있으며 부분 중복성 제거 패스에 포함됩니다. 이 최적화는 루프의 수명 내내 변경되지 않는 값을 계산하는 루프에서 지침을 제거합니다.

--- 끝 발췌-

GCC에 대한 최적화 :

https://www.in.redhat.com/software/gnupro/technical/gnupro_gcc.php3

문제를 완전히 회피하지 않겠습니까? boost_foreach

#include <boost/foreach.hpp>

std::vector<double> vec;

//...

BOOST_FOREACH( double &d, vec)
{
    std::cout << d;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top