비용은 무엇입의 포인터를 사용하여 회원 기능을 대스위치?

StackOverflow https://stackoverflow.com/questions/113150

  •  02-07-2019
  •  | 
  •  

문제

나는 다음과 같은 상황:


class A
{
public:
    A(int whichFoo);
    int foo1();
    int foo2();
    int foo3();
    int callFoo(); // cals one of the foo's depending on the value of whichFoo
};

에서는 현재 구현장의 가치 whichFoo 데이터 구성원에서 생성자 및 사용 switchcallFoo() 의 결정 foo 의를 호출합니다.또는,사용할 수 있는 switch 에서 생성자를 저장하는 포인터를 오른쪽 fooN() 라고서 callFoo().

나의 질문은 방법은 더 많은 효율을 경우 객체의 클래스는 단지 건설,한 번하는 동안 callFoo() 라고 매우 많습니다.그래서 첫 번째 경우에서 우리는 여러 번 실행 스위치 문의하면서 두 번째 하나만 있으로 전환,그리고 여러 번 호출의 구성원이 기능을 사용하여 포인터이다.내가 알고있는 호출하면 구성원 기능을 사용하여 포인터가 보다 느린 단지 그것이 직접 있습니다.누군가 알고 있는 경우 이러한 오버헤드가 발생하지 않보다 더 많거나 적은 비용의 switch?

설명:나는 당신은 정말 알고 있는 접근 방식은 더 나은 성능을 때까지 당신은 그것을 시도 및 시간니다.그러나 이 경우에는 내가 이미 방법 1 을 구현하고 싶었을 경우 접근 2 을 더 효율적으로 할 수 있도 원칙으로 합니다.그것은이 나타납 될 수 있다는,그리고 지금 그것이 나를 귀찮게 그것을 구현하고 그것을 시도하십시오.

아,그리고 내가 또한 같은 방법 2 에 대한 더 나은 미학적 이유입니다.나는 내가 찾는 것은 정당성을 구현합니다.:)

도움이 되었습니까?

해결책

어떻게 확실히 당신은 당신을 호출하면 구성원 기능을 통해 포인터가 느리다 그냥 부르는 그것을 직접?을 측정할 수 있는 차이가 있나요?

일반적으로,당신은하지 않아야에 의존하고 직관을 만들 때 성능 평가.함께 앉아서 당신의 컴파일러와 타이밍 기능,실제로 측정 다른 선택이다.당신은 놀랄 수 있습니다!

더 많은 정보:거기에 훌륭한 문서 멤버 함수 포인터이고 가장 빠르게 가능한 C++대리 는 매우 깊은 세부사항의 이행에 대한 구성원 기능 포인터입니다.

다른 팁

이와 같이 작성 할 수 있습니다:

class Foo {
public:
  Foo() {
    calls[0] = &Foo::call0;
    calls[1] = &Foo::call1;
    calls[2] = &Foo::call2;
    calls[3] = &Foo::call3;
  }
  void call(int number, int arg) {
    assert(number < 4);
    (this->*(calls[number]))(arg);
  }
  void call0(int arg) {
    cout<<"call0("<<arg<<")\n";
  }
  void call1(int arg) {
    cout<<"call1("<<arg<<")\n";
  }
  void call2(int arg) {
    cout<<"call2("<<arg<<")\n";
  }
  void call3(int arg) {
    cout<<"call3("<<arg<<")\n";
  }
private:
  FooCall calls[4];
};

계산 실제적인 함수 포인터는 선형 및 고속:

  (this->*(calls[number]))(arg);
004142E7  mov         esi,esp 
004142E9  mov         eax,dword ptr [arg] 
004142EC  push        eax  
004142ED  mov         edx,dword ptr [number] 
004142F0  mov         eax,dword ptr [this] 
004142F3  mov         ecx,dword ptr [this] 
004142F6  mov         edx,dword ptr [eax+edx*4] 
004142F9  call        edx 

참고가 없어도 수정하는 실제 기능을 수 있습니다.

해 내 이 코드를 asm 에 의해 생성 switch.이 switch 버전이 제공되지 않을 향상시키고 싶습니까?

에 대답을 묻는 질문:에서 최고의 세밀한 수준에 대한 포인원 기능을 더 잘 수행 할 수 있습니다.

주소를 부탁받지 않는 질문:무엇이"나"는 말까요?대부분의 경우게 될 것으로 예상 차이점을 무시할 수 있습니다.에 따라 클래스고,그러나,차이 중요 할 수 있습니다.성능 테스트에 대한 걱정하기 전에 차이를 분명히 오른쪽 첫 단계입니다.

는 경우에 당신은 유지하는 것을 사용하여 스위치가 완벽하게,당신은 아마를 넣어야에서 논리는 도우미는 방법과는 경우 호출에서 생성자입니다.또한,이것은 고전적인 경우 전략 패턴.을 만들 수 있습 인터페이스(또는 추상 클래스)이라는 IFoo 있는 방법 중 하나로 푸의 서명이 있습니다.당신이 생성자에 의 인스턴스 IFoo(생성자 속국 주입 구현 foo 방법입니다.당신이 개인 IFoo 는 것으로 설정이 생성자,그리고 모든 시간은 당신이 원하는 호출 푸 당신은 당신의 IFoo 의 버전입니다.

참고:나는 일을 하지 않았으로 C++이후 대학,그래서 나의 링고 떨어져 수 있습니다,여기에 ut 일반적인 아이디어를 개최를 위한 가장 OO 언어입니다.

는 경우는 예제 코드는 다음을 방문 클래스 디자인을 기준으로 합니다.값을 전달을 생성자,그리고 사용하는 것을 변경하는 행동은 정말을 만드는 것과 같은 서브 클래스.리팩터링을 고려하여 더욱 분명하게 명시되어 있습니다.의 효력이 그렇게 하는 코드를 사용하여 종료하는 함수 포인터이(모든 가상 방법은 정말,는 함수 포인터에서 뛰어 테이블).

는 경우,그러나 당신의 코드 그냥 간단한 예제는지 여부를 물어,일반적으로 점프,테이블보다 더 빠른 스위치는 다음 문을 직감을 따라고 말할 것 뛰어 테이블은 빨리,하지만 당신은에 의존하는 컴파일러의 최적화 단계입니다.하지만 경우에는 성능이 정말 이러한 관심에 의존하지 직관-노 테스트 프로그램 및 테스트,또는 생성된 assembler.

한 가지는 확실 switch 문 것보다 느리게 점프하는 테이블.는 이유는 최고의 컴파일러의 최적화를 할 수 있는 것이 너무 차례는 일련의 조건 테스트(예:는 스위치)으로 점프하는 테이블.그래서 만약 당신이 정말로 원하는 특정,을 컴파일러의 결정 과정과 사용하는 점이다.

소리처럼 당신 callFoo 순수한 가상의 기능과 몇 가지를 만들의 하위 클래스 A.

지 않는 한 당신이 정말로 필요한 속도,광범위한 프로파일링 및 계측,그리고 결정되는 통화 callFoo 은 정말 병목 현상이 발생했습니다.신가?

함수 포인터는 거의 항상 연결-ifs.그들은 깔끔한 코드,그리고 거의 항상 빠르게(아마도 제외하고는 경우에만 사이의 선택 두 기능은 항상 정확하게 예측).

나는 생각해야한다는 포인터가 빨라집니다.

현대 Cpu prefetch 지침;잘못된 예측 지점에 넘치는 캐시 즉,그것은 노점이있는 동안 그것은 리필을 주시기 바랍니다.포인터를 넣은 사람은 그렇게 하지 못합니다.

물론,측정해야 합니다.

을 최적화하고 필요한 경우에만

먼저:대부분의 시간을 당신은 가능성이 가장 높은 걱정하지 않는 차이는 아주 작은 것입니다.는지 확인 최적화에 이 호출은 정말 의미가 처음이다.는 경우에만 귀하의 측정 표시기는 것은 정말 뜻깊은 시간을 보냈다에서 호출 오버헤드를 진행합 최적화(뻔뻔한 플러그-다. 을 최적화하는 방법을 확인하는 응용 프로그램은 그것을 빠르니까? 약)최적화이 중요하지 않아보세요 더 많이 읽을 수 있는 코드입니다.

간접화 비용에 따라 달라집 대상 플랫폼

를 결정했다면 그것은 가치를 적용하는 낮은 수준의 최적화,다음은 이해하는 시간을 당신의 타겟 플랫폼입니다.비용을 피할 수 있습니다 여기를 지점 misprediction penalty.에 현대적인 x86/x64CPU 이 misprediction 될 가능성이 매우 작은(그들은 예측할 수 있다 간접 통화를 아주 잘 대부분의 시간),하지만 타겟팅할 때 사용하거나 다른 RISC 플랫폼,간접화/점프 없는 자주에서 예측되는 모든 피하고 그들을 일으킬 수 있는 뜻깊은 성과를 얻을.또한 참조 가상화 비용에 따라 달라집 플랫폼.

컴파일러를 구현할 수 있는 스위치를 사용하여 점프,테이블

하나 잡았다:스위치 될 수 있습으로 구현되는 간접 부르(테이블을 사용하여)뿐만 아니라,특히 간에 전환할 때 많은 가능한 값입니다.이러한 스위치는 전시 동 misprediction 가상 기능입니다.이 최적화 신뢰할 수 있는,하나는 아마 사용하여 선호하는 경우에는 스위치를 위한 가장 일반적인 경우입니다.

타이머를 사용하여 볼 수있는 빠르다.지 않는 한 이 코드를 수상한 다음 그것의 가능성을 알 수 있다.

해야 하는 실행하는 경우에는 코드에서 생성자를 하는 경우 contruction 실패하는 메모리 누수.

이 기술은 많이 사용됩 Symbian OS:http://www.titu.jyu.fi/modpa/Patterns/pattern-TwoPhaseConstruction.html

는 경우에만 호출 callFoo()한 번보 가능성 함수 포인터를 느리게 될 것입니다에 의해 하찮은 금액입니다.를 호출하는 경우 그것은 많은 시간다 가능성 함수 포인터이다 빠르게 의 사소한 금액(필요로 하지 않기 때문에 계속하는 스위치를 통해).

어느 쪽이든 모습에서 조립된 코드를 확실히 알아내기 위하여 그것은 당신이 무엇을 하 고 생각하는 그것을하고있다.

하나는 자주 간과 활용하는 스위치(도 통해 분류하고 색인)은 당신이 알고 있는 경우는 특정 값이 사용되는 대부분의 경우입니다.그것은 쉽게 위치하는 가장 일반적인은 먼저 확인합니다.

ps.을 강화하는 그의 대답에 대해 걱정하는 경우 속도 측정합니다.보고 어셈블러에 도움이 되지 않을 때 Cpu 가 프리패치/분기 예측하고 파이프라인 마 등

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top