C ++ 11의 '자동'을 사용하여 성능을 향상시킬 수 있습니까?
auto
C ++ 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_iterator
은 std::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
'Programing' 카테고리의 다른 글
목록에서 여러 데이터 프레임을 동시에 병합 (0) | 2020.04.19 |
---|---|
여러 열을 참조하는 팬더 '적용'기능이 작동하지 않는 이유는 무엇입니까? (0) | 2020.04.19 |
MySQL 계층 재귀 쿼리를 만드는 방법 (0) | 2020.04.19 |
전체 폴더를 반복적으로 저장소에 추가 (0) | 2020.04.19 |
스칼라의 케이스 객체와 열거 (0) | 2020.04.19 |