Programing

C ++ 11의 '자동'을 사용하여 성능을 향상시킬 수 있습니까?

lottogame 2020. 4. 19. 13:51
반응형

C ++ 11의 '자동'을 사용하여 성능을 향상시킬 수 있습니까?


autoC ++ 11 유형이 정확성과 유지 관리 성을 향상시키는 이유를 알 수 있습니다 . 나는 또한 성능을 향상시킬 수 있다는 것을 읽었 지만 (허브 스퍼트에 의해 거의 항상 자동 ), 나는 좋은 설명을 그리워합니다.

  • 어떻게 auto성능 향상시킬 수 있습니까?
  • 누구나 모범을 보여줄 수 있습니까?

auto자동 암시 적 변환피함으로써 성능을 향상시킬 수 있습니다 . 내가 찾은 예는 다음과 같습니다.

std::map<Key, Val> m;
// ...

for (std::pair<Key, Val> const& item : m) {
    // do stuff
}

버그가 보입니까? 여기서 우리는 const 참조로 맵의 모든 항목을 우아하게 취하고 새로운 범위-범위 표현식을 사용하여 의도를 명확하게 나타내지 만 실제로 모든 요소를 복사한다고 생각 합니다. 때문입니다 std::map<Key, Val>::value_type입니다 std::pair<const Key, Val>,하지 std::pair<Key, Val>. 따라서 우리가 (내재적으로) 가지고있을 때 :

std::pair<Key, Val> const& item = *iter;

기존 객체에 대한 참조를 가져 와서 그대로 두는 대신 유형 변환을 수행해야합니다. 다음과 같이 암시 적 변환이 가능한 한 다른 유형의 객체 (또는 임시)에 대한 const 참조를 사용할 수 있습니다.

int const& i = 2.0; // perfectly OK

형식 변환은 a const Key를 a 로 변환 할 수있는 것과 같은 이유로 허용되는 암시 적 변환 Key이지만,이를 허용하려면 새 형식의 임시를 구성해야합니다. 따라서 효과적으로 루프가 수행합니다.

std::pair<Key, Val> __tmp = *iter;       // construct a temporary of the correct type
std::pair<Key, Val> const& item = __tmp; // then, take a reference to it

(물론 실제로는 __tmp개체 가 없으며 단지 설명을 위해 존재합니다. 실제로 이름이없는 임시 개체 item는 수명 기간 동안 바인딩됩니다 .)

그냥 다음으로 변경 :

for (auto const& item : m) {
    // do stuff
}

방금 우리에게 많은 사본을 저장했습니다. 이제 참조 된 유형이 이니셜 라이저 유형과 일치하므로 임시 또는 변환이 필요하지 않으므로 직접 참조 할 수 있습니다.


때문에 auto초기화 식의 추론 유형, 반군 유형 변환은 없습니다. 템플릿 알고리즘과 함께 사용하면 유형을 직접 구성 할 때보 다, 특히 이름을 지정할 수없는 유형의 표현식을 처리 할 때보 다 더 직접적인 계산을 얻을 수 있습니다.

일반적인 예는 다음과 같이 사용됩니다 std::function.

std::function<bool(T, T)> cmp1 = std::bind(f, _2, 10, _1);  // bad
auto cmp2 = std::bind(f, _2, 10, _1);                       // good
auto cmp3 = [](T a, T b){ return f(b, 10, a); };            // also good

std::stable_partition(begin(x), end(x), cmp?);

cmp2하고 cmp3, 당신이 만들 경우 반면에, 비교 호출을 인라인 할 수있는 전체 알고리즘 std::function객체가 아니라 통화가 인라인 될 수없는,하지만 당신은 함수 래퍼의 유형 - 삭제 내부 다형성 조회를 통과해야합니다.

이 주제의 또 다른 변형은 다음과 같이 말할 수 있다는 것입니다.

auto && f = MakeAThing();

이것은 항상 함수 호출 표현식의 값에 바인딩 된 참조이며 추가 오브젝트를 구성하지 않습니다. 반환 된 값의 유형을 모르는 경우 다음과 같은 방법으로 새 ​​객체 (임시로)를 생성해야 할 수 있습니다 T && f = MakeAThing(). (또한, auto &&리턴 타입이 움직일 수없고 리턴 값이 prvalue 때에도 작동합니다.)


두 가지 범주가 있습니다.

auto유형 삭제를 피할 수 있습니다. 람다와 같은 이름없는 유형과 거의 이름없는 유형 (결과 std::bind또는 다른 표현 템플릿과 같은)이 있습니다.

없으면 auto데이터를 지우고 입력해야합니다 std::function. 유형 삭제에는 비용이 있습니다.

std::function<void()> task1 = []{std::cout << "hello";};
auto task2 = []{std::cout << " world\n";};

task1가능한 힙 할당, 인라인 어려움 및 가상 함수 테이블 호출 오버 헤드와 같은 유형 삭제 오버 헤드가 있습니다. task2없습니다. 람다 유형 삭제없이 저장 하려면 자동 또는 다른 유형의 유형 추론이 필요합니다. 다른 유형은 너무 복잡하여 실제로 필요합니다.

둘째, 유형이 잘못 될 수 있습니다. 경우에 따라 잘못된 유형이 완벽하게 작동하지만 사본이 발생할 수 있습니다.

Foo const& f = expression();

경우 컴파일 expression()반환 Bar const&또는 Bar심지어 Bar&어디 Foo에서 구성 할 수있다 Bar. 임시 Foo가 생성 된 다음에 바인딩되며 f수명이 연장 될 때까지 연장 f됩니다.

프로그래머는 Bar const& f복사를 의도하거나 의도하지 않았지만 복사는 사본에 관계없이 작성됩니다.

가장 일반적인 예는의 유형이지만이 유형 *std::map<A,B>::const_iteratorstd::pair<A const, B> const&그렇지 std::pair<A,B> const&않지만 오류는 자동으로 성능 비용이 발생하는 오류 범주입니다. 당신은을 구성 할 수 std::pair<A, B>A로부터 std::pair<const A, B>. (지도의 키는 const입니다. 편집하는 것은 좋지 않습니다.)

@Barry와 @KerrekSB는이 두 가지 원칙을 먼저 답했습니다. 이것은 단순히 예제 중심이 아닌 문제를 목표로하는 표현으로 한 가지 답변으로 두 가지 문제를 강조하려는 시도입니다.


기존의 세 가지 답변은 auto도움을 사용 하면 "의도적으로 비관적으로 비관 할 가능성이 줄어들어" 성능이 향상됩니다.

동전에는 뒤집힌면이 있습니다. auto기본 객체를 반환하지 않는 연산자가있는 객체와 함께 사용하면 잘못된 (아직 컴파일 가능하고 실행 가능한) 코드가 발생할 수 있습니다. 예를 들어, 이 문제는 사용하는 방법을 묻는 auto, 고유치 라이브러리를 사용하여 다른 (잘못된) 결과 준 즉, 다음 줄을

const auto    resAuto    = Ha + Vector3(0.,0.,j * 2.567);
const Vector3 resVector3 = Ha + Vector3(0.,0.,j * 2.567);

std::cout << "resAuto = " << resAuto <<std::endl;
std::cout << "resVector3 = " << resVector3 <<std::endl;

다른 출력 결과. 분명히 이것은 대부분 Eigens 게으른 평가 때문이지만 코드는 (라이브러리) 사용자에게 투명해야합니다.

여기서 성능에 큰 영향을 미치지는 않았지만 auto의도하지 않은 비관 화를 피하기 위해 사용 하는 것은 조기 최적화 또는 적어도 잘못된 것으로 분류 될 수 있습니다.

참고 URL : https://stackoverflow.com/questions/32510183/can-the-use-of-c11s-auto-improve-performance

반응형