2013-06-12 2 views
1

계산 시간에 이러한 차이가있는 이유를 다음 코드 (최적화되지 않음)와 함께 설명 할 수 있습니까? 나는 RVO 대 이동 건설을 의심하지만 실제로는 잘 모르겠습니다.자동 루프 및 최적화

일반적으로 이런 경우에 가장 좋은 방법은 무엇입니까? 비 POD 데이터를 초기화 할 때 루프의 자동 선언은 나쁜 습관으로 간주됩니까?

루프 내부 자동 사용 :

std::vector<int> foo() 
{ 
    return {1,2,3,4,5}; 
} 

int main() 
{ 
    for (size_t i = 0; i < 1000000; ++i) 
     auto f = foo(); 
    return 0; 
} 

출력 :

사용자 0.00s 시스템 97 % CPU 0.177 총

0.17s ./a.out

루프 외부의 벡터 인스턴스 :

std::vector<int> foo() 
{ 
    return {1,2,3,4,5}; 
} 

int main() 
{ 
    std::vector<int> f; 

    for (size_t i = 0; i < 1000000; ++i) 
     f = foo(); 
    return 0; 
} 

출력 : 나는 이동 - 건설 대 망막 정맥 폐쇄가 의심

사용자 0.00s 시스템 99 %의 CPU 0.325 총

+2

를 참조하십시오. 이것은 의도 된 것입니까? 오렌지와 오렌지를 비교한다면,'std :: vector f'를 루프 안에 넣으면 안되나요? – legends2k

+0

이동 건설이 훨씬 빠르다고 생각되면 고유 한 벡터 클래스를 사용하고 이동 생성자를 복사 생성자에 전달하고 다시 측정하십시오. 아니면 어셈블리를보고 그것이 무엇을하고 있는지보십시오. 또는 클래스의 복사/이동 생성자와 할당 연산자에 카운터를 추가하고 실제로 호출 된 것을 확인하십시오. – Useless

+3

또한 : 가짜 벤치 마크 경고. 괜찮은 최적화 '기술'을 가진 컴파일러는 모든 루프를 최적화 할 수 있습니다. – sehe

답변

2

0.32s ./a.out하지만, 나는 정말로 모른다.

예, 그런 일이 거의 확실합니다. 첫 번째 경우는 함수의 반환 값에서 변수를 초기화합니다.이 경우 함수는 함수를 초기화하여 함수를 초기화 할 수 있습니다. 두 번째 경우는 반환 값에서 이동합니다. 과제는 생략 할 수 없습니다. 나는 당신이 명시 적으로 그것을 비활성화하지 않는 한, GCC가 최적화 레벨 0에서도 elision을 수행한다고 생각합니다.

마지막 사례 (질문에서 이제 제거 된 -O3)에서 컴파일러는 루프에 부작용이없는 것으로보고 완전히 제거합니다.

벡터 volatile을 선언하고 최적화를 사용하여 컴파일하면 더 유용한 벤치 마크를 얻을 수 있습니다 (또는 아닐 수도 있음). 이렇게하면 컴파일러가 실제로 더 잘 알고 있다고 생각하더라도 각 반복마다 실제로 생성/할당하게됩니다.

POD가 아닌 데이터를 초기화 할 때 루프의 자동 선언이 좋지 않은 것으로 간주됩니까?

아니오; 무엇보다도 필요한 가장 좁은 범위에서 사물을 선언하는 것이 더 나은 방법입니다. 따라서 루프에서만 필요하면 루프에서 선언하십시오. 상황에 따라 루프 외부에 복잡한 객체를 선언하여 각 ​​반복에서 반복 객체를 다시 작성하지 않아도 성능을 향상시킬 수 있습니다. 성능 이점 (a)가 존재하고 (b)가 지역 손실의 가치가 있다는 것을 확신 할 때만 그렇게합니다.

+0

고마워요! 매우 유용한 특히 마지막 문장 :) – 3XX0

1

예를 들어 auto과 관련이없는 것으로 보입니다. 당신은 두 가지 프로그램을 썼습니다.

for (size_t i = 0; i < 1000000; ++i) 
    auto f = foo(); 

for (size_t i = 0; i < 1000000; ++i) 
    std::vector<int> f = foo(); 

에 해당하지만

- 의미, 당신은 새로운 벡터를 생성 (그리고 이전을 파괴) . 그리고 예, foo-RVO를 사용하여 구현하지만 여기에 요점이 없습니다. 외부 루프가 f의 공간을 차지할 장소에 새로운 vector을 계속 만듭니다.

코드 조각

std::vector<int> f; 
for (size_t i = 0; i < 1000000; ++i) 
    f = foo(); 

은 기존의 벡터에 할당를 사용합니다. 그리고 예, RVO를 사용하면 foo에 따라에 따라 무브먼트가 할당 될 수 있으며 이는 귀하의 경우이므로 빠른 것으로 기대할 수 있습니다. 하지만 여전히 이고 다른 것은 리소스 관리에있어 항상 하나 인 f입니다.

는하지만 당신은 매우 아름답게 여기 보여 않는 것은 종종 일반적인 규칙을 가능한 한 그들의 사용에 가까운

선언 변수를 수행하는 것이 합리적이다. 다른에만 할당이있는 동안

는 하나 개의 루프가의 선언시 초기화에서 this Discussion