6

템플릿 방법 디자인 패턴 다음과 같은 코드를 생각해인라인 개체 값의 의미가있는 방법 가상 함수

class A { 
    public: 
     void templateMethod() { 
      doSomething(); 
     } 
    private: 
     virtual void doSomething() { 
      std::cout << “42\n”; 
     } 
}; 
class B : public A { 
    private: 
     void doSomething() override { 
      std::cout << “43\n”; 
     } 
}; 

int main() { 
    // case 1 
    A a; // value semantics 
    a.templateMethod(); // knows at compile time that A::doSomething() must be called 

    // case 2 
    B b; // value semantics 
    b.templateMethod(); // knows at compile time that B::doSomething() must be called 

    // case 3 
    A& a_or_b_ref = runtime_condition() ? a : b; // ref semantics 
    a_or_b_ref.templateMethod(); // does not know which doSomething() at compile time, a virtual call is needed 
    return 0; 
} 

컴파일러는 인라인/할 수 있는지 궁금하고는 "해봐요을 (unvirtualize) "멤버 함수를 사용합니다. templateMethod()에 대해 3 가지 다른 바이너리 코드를 생성하는 경우 가능합니다. 하나는 인라인이없고 다른 하나는 A :: doSomething() 또는 B :: doSomething() 인라인 (케이스 3, 1 및 2에서 각각 호출해야 함)

표준에 따라 최적화가 필요한지 알고 있습니까? 어떤 컴파일러가 그것을 구현한다면? 나는 CRT 패턴과 가상이 같은 종류의 효과를 얻을 수 있지만 그 의도는 명확하지 않다는 것을 알고 있습니다.

+0

심지어 공격적인 최적화 컴파일러의 대부분이 정적 버전을 인라인으로 실패 나에게 보인다 ... 즉시 컴파일러를 변경 한 것이 아무 것도 표시했다 인라인 될 수없는 동일한 서명을 가진 함수의 예가 많이 있습니다. 예를 들어, fucions에서 외부 메모리에 액세스하는 경우 : 'cout << * p', 여기서 'p'는 클래스의 멤버입니다. doSomething()의 서명은 예제와 동일하지만 인라이닝을 수행 할 수 없습니다. 그러나 그것은 단지 의견 일뿐입니다. –

+0

글쎄 어쩌면 내가 틀렸어.하지만 난 항상 어떤 기능도 기술적으로 인라인 될 수 있다고 생각했다. 가상이나 재귀가 아니라면 조건없이 인라인 될 수있다. 귀하의 예제에서 필자는 함수가 가상이 아닌 경우 컴파일러가 인라인 할 수없는 이유를 알지 못합니다. –

+0

흠, 필자는 항상 인라인 코드를 직접 붙여 넣는 것이기 때문에 기술적으로 'cout << *(this-> p)'문자열을 가진 코드가 있습니다. 해당 코드에서 'this'포인터에 대한 정보가 필요하지만 인라인을 사용하면이를 놓칠 수 있습니다. 내가 잘못? –

답변

1

표준은 일반적으로 최적화가 필요하지 않습니다 (때로는 허용되지 않는 경우도 있음). 그것은 결과를 명시하고 그것을 달성하는 최선의 방법을 찾아내는 것은 컴파일러에 달려 있습니다.

세 가지 경우 모두 templateMethod이 인라인 될 것으로 예상됩니다. 컴파일러는 자유롭게 추가 최적화를 수행 할 수 있습니다. 처음 두 경우에는 this의 동적 유형을 알고 있기 때문에 doSomething에 대해 비 가상 호출을 생성 할 수 있습니다. (나는 그 전화를 인라인하기를 기대한다.)

생성 된 코드를 보시고 직접 확인하십시오.

+0

Jarod42 주석을 기반으로 컴파일러가 case 3에 대해 컴파일 할 때 무엇을 호출해야 하는지를 알 수 없도록 코드를 편집했습니다. –

+0

그럼이 경우는 인라인되지 않습니다. 수정 된 답변 –

0

최적화는 컴파일러가 표준이 아닌 문제입니다. 최적화가 비 존경 또는 가상 기능의 원칙을 이끌어내는 경우 큰 문제가됩니다. 그래서 세번째 경우

:

// case 3 
A& b_ref = b; // ref semantics 
b_ref.templateMethod(); 

실제 객체는 B, 및 사용 포인터의 참조가 무엇이든 B 클래스에 정의 된 것이어야라는 실제 기능입니다.

그리고 제대로 43 내 컴파일러 표시 - 내가이 할 수 있기 때문에,

+0

제 1의 경우와 2의 경우, 컴파일러는 객체를 컴파일 할 때를 알고 있으므로 가상 함수 객체 코드를 생성 할 필요가 없습니다. 물론 3 번 사례와 같이 알지 못하면 가상 호출 메커니즘을 존중해야합니다. 그러나 올바른 동작과 완전한 최적화로 세 가지 경우를 수행하려면 3 개의 다른 templateMethod() 객체 코드를 생성해야합니다. –

+0

@ Bérenger 3 가지 버전의'templateMethod'를 생성 할 필요가 없습니다. 즉, 호출을 함수 본문으로 바꾸고 세 가지 다른 위치에서 호출을 대체 한 다음 결과 코드를'main' 컴파일의 일부로 최적화합니다. –

+0

@ Bérenger : 필자는 컴파일러 개발자의 문제라고 생각한다. 최적화 된 코드를 분석 하려다가 곧 포기했습니다. 최적화되지 않은 코드보다 빠르지 만 소스 코드로 작성한 코드를 거의 찾지 못했습니다. 이제는 성능 문제가 있고 병목을 확인한 후에 만 ​​낮은 수준의 최적화를 시도합니다. –