[C++] functor가 function보다 빠를 수 있는 요인

ixevexi의 이미지

어디선가 읽었던거 같은데 헷깔려서 질문을 합니다
방금 TC++PL과 EC++ MEC++모두 대략 훑어봤는데
functor가 왜 function보다 빠른지에 대해서는 별 말이 없네요

다음의 한구절만이 있습니다.

Stroustrup wrote:

A suitably-defined object serves as well as - and often better than - a function. For example, it is easier to inline the application operator of a class than to inline a function passed as a pointer to a function.
Consequently, function objects often execute faster than do ordinary functions

제가 이해한 바가 맞다면 펑션 포인터로 넘겨지는 함수보다 어플리케이션 오퍼레이터( operator ()() 로 이해했습니다) 를 가진 클래스의 오퍼레이터가 인라인 하기 쉽기때문에 많은 경우 빠르다고 되어있습니다.

제가 이런 질문을 하게 되는게 다음과 같은 글을 보았기 때문입니다.
foreach의 경우 마지막 세번째 인자를 함수객체 아니면 함수를 받게 되는데 이때 함수객체를 넘기면 인라이닝이 된다는 소리를 들었습니다.

위의 인용한 말에 따르면 그것이 거짓만은 아닐듯 한데 그것이 '항상'되는 것인지도 궁금하고 과연 위와같은 상황을 염두에 두고 하는 말인지 궁금합니다

또한 functor가 어떻게 더 빠를 수 있는지 다른 요인도 궁금하고요 ^^
그것들이 어디에 쓰여있는지도 몹시 궁금하네요

lifthrasiir의 이미지

ixevexi wrote:
어디선가 읽었던거 같은데 헷깔려서 질문을 합니다
방금 TC++PL과 EC++ MEC++모두 대략 훑어봤는데
functor가 왜 function보다 빠른지에 대해서는 별 말이 없네요

다음의 한구절만이 있습니다.

Stroustrup wrote:

A suitably-defined object serves as well as - and often better than - a function. For example, it is easier to inline the application operator of a class than to inline a function passed as a pointer to a function.
Consequently, function objects often execute faster than do ordinary functions

제가 이해한 바가 맞다면 펑션 포인터로 넘겨지는 함수보다 어플리케이션 오퍼레이터( operator ()() 로 이해했습니다) 를 가진 클래스의 오퍼레이터가 인라인 하기 쉽기때문에 많은 경우 빠르다고 되어있습니다.

제가 이런 질문을 하게 되는게 다음과 같은 글을 보았기 때문입니다.
foreach의 경우 마지막 세번째 인자를 함수객체 아니면 함수를 받게 되는데 이때 함수객체를 넘기면 인라이닝이 된다는 소리를 들었습니다.

위의 인용한 말에 따르면 그것이 거짓만은 아닐듯 한데 그것이 '항상'되는 것인지도 궁금하고 과연 위와같은 상황을 염두에 두고 하는 말인지 궁금합니다

또한 functor가 어떻게 더 빠를 수 있는지 다른 요인도 궁금하고요 ^^
그것들이 어디에 쓰여있는지도 몹시 궁금하네요

functor에서 operator()를 inline으로 설정했다면, -- 그리고 컴파일러가 inline을 처리해 준다면 -- for_each 같은 곳에서 operator()를 호출하는 과정이 인라인화되기 때문에 함수 호출에 드는 부하가 사라지고, 더불어 필요에 따라서는 그 상황에서 더 최적화될 수 있습니다. 반면에 함수 포인터로 넘겨 줄 경우 컴파일러가 웬만큼 똑똑하지 않으면 그걸 최적화하기 힘들 것이고, 따라서 함수 호출에 드는 부하와 (인라인화하면 사라질 수도 있는) 추가적인 부담이 들게 됩니다. 아, 하지만 functor라도 operator()가 인라인화되지 않는다면 그게 그겁니다.

혹시나 싶지만... 간단한 예를 들어 보겠습니다.

char caesarFunction(char x) {
    char xx = x | 32;
    if ('a' <= xx && xx <= 'w') return x + 3;
    if ('x' <= xx && xx <= 'z') return x - 23;
    return x;
}

struct caesarFunctor {
    char operator(char x) {
        char xx = x | 32;
        if ('a' <= xx && xx <= 'w') return x + 3;
        if ('x' <= xx && xx <= 'z') return x - 23;
        return x;
    }
};

template <typename _Func>
void encryptString(char *str, _Func func) {
    while(*str) {
        *str = func(*str);
        str++;
    }
}

만약 컴파일러가 인라인화를 지원한다면, 위 코드는 (대략) 다음과 같이 바뀌어 처리됩니다. 컴파일러마다 실제 결과는 다를 수 있지만 차이가 드러 난다는 걸 알 수 있습니다.
// encryptString(str, caesarFunction); 의 해석
void encryptStringWithFunction(char *str) {
    while(*str) {
        *str = caesarFunction(*str);
        str++;
    }
}

// encryptString(str, caesarFunctor()); 의 해석
void encryptStringWithFunctor(char *str) {
    while(*str) {
        char x = *str;
        char xx = x | 32;
        if ('a' <= xx && xx <= 'w') *str = x + 3;
        else if ('x' <= xx && xx <= 'z') *str = x - 23;
        str++;
    }
}

보시다시피 functor를 사용한 코드는 컴파일러가 최적화할 여지가 더 많아지고, 이는 속도 향상으로 나타납니다. (위의 경우 맨 마지막의 불필요한 *str = x; 부분이 사라졌다는 걸 알 수 있습니다. 최적화가 안 되었다고 하더라도 함수 호출 부하는 사라지겠죠.)

functor는... 말 그대로 여러 군데에서 많이 쓰입니다. STL에서 함수 비스무리한 걸 받을 만한 대부분의 곳에서 functor를 쓸 수 있다고 생각하셔도 될 것 같습니다.

- 토끼군

gimmesilver의 이미지

함수의 경우 해당 함수의 포인터가 인자로 넘어가고 실제 함수 호출 지점에서는 단지 함수의 포인터 정보만을 알 수 있기 때문에 인라인 화가 힘들지만 함수 객체는 함수 포인터가 아닌 객체가 넘어가고 호출되는 부분에서 객체의 연산자 함수가 직접 호출되기 때문에 해당 함수가 호출 시점에서 인라인화가 될 수 있습니다.
때문에 함수 객체가 함수보다 최적화에 유리합니다.
그 외에도 함수 객체는 상태값을 가질 수 있다는 점에서 유연성과 최적화에 유리합니다.

------------------------
http://agbird.egloos.com

doldori의 이미지

속도의 차이가 inlining 때문임은 토끼군님이 잘 설명해 주셨는데,
이것이 항상 되는 것은 아닙니다. 전적으로 컴파일러의 품질에 달린 것이지요.
또한 inlining이 되었다고 해서 항상 빨라지는 것도 아니고요.
더 자세한 내용은 Effective STL, Item 46을 참고하십시오.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.