람다 및 일반 함수에 대한 컴파일러 최적화
그의 책 "The C Standard Library(Second Edition)"에서 Nicolai Josuttis는 주장합니다. 람다는 일반 함수보다 컴파일러에 의해 더 잘 최적화될 수 있습니다. 람다와 일반 함수가 모두 인라인될 수 있다는 점을 고려하면 이는 직관에 어긋나는 것처럼 보일 수 있습니다. 그러나 람다의 경우 더 나은 최적화를 가능하게 하는 미묘한 차이가 있습니다.
차이점: 함수 개체와 함수 포인터
람다는 함수 객체인 반면, 일반 함수는 본질적으로 함수 포인터입니다. 함수 템플릿에 람다를 전달하면 해당 개체에 대한 새 함수가 인스턴스화됩니다. 이를 통해 컴파일러는 간단하게 람다 호출을 인라인할 수 있습니다.
반대로 일반 함수를 함수 템플릿에 전달하면 함수 포인터가 전달됩니다. 컴파일러는 역사적으로 함수 포인터를 통한 호출을 인라인하는 데 어려움을 겪었습니다. 이론적으로는 인라인될 수 있지만 주변 함수도 인라인된 경우에만 발생합니다.
예
다음 함수 템플릿을 고려하세요.
template <typename Iter, typename F> void map(Iter begin, Iter end, F f) { for (; begin != end; ++begin) *begin = f(*begin); }
람다를 사용하여 호출:
int a[] = { 1, 2, 3, 4 }; map(begin(a), end(a), [](int n) { return n * 2; });
고유한 인스턴스화가 발생합니다.
template <> void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) { for (; begin != end; ++begin) *begin = f.operator()(*begin); }
컴파일러는 람다의 연산자()를 식별하고 이에 대한 간단한 인라인 호출을 식별할 수 있습니다.
그러나 함수 포인터로 호출할 경우:
map(begin(a), end(a), &multiply_by_two);
인스턴스화는 다음과 같습니다.
template <> void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) { for (; begin != end; ++begin) *begin = f(*begin); }
여기서 f는 맵이 호출될 때마다 다른 함수를 참조하므로 맵 자체가 인라인되지 않는 한 컴파일러는 호출을 인라인화하지 않습니다.
결론
함수 객체로서 고유한 유형의 람다를 사용하면 컴파일러가 특정 함수 인스턴스화를 생성하고 해당 호출을 원활하게 인라인할 수 있습니다. 이 향상된 최적화 기능은 람다를 일반 함수와 구별하므로 코드 성능과 효율성을 향상시키기 위해 선호되는 선택이 됩니다.
위 내용은 컴파일러로 일반 함수보다 람다를 더 잘 최적화할 수 있나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!