2012-01-14 3 views
4

기본적인 생각은 모두 동일한 똑같은 일을하지만 약간 다른 방식으로 클래스의 "가족"이 있다는 것입니다. 이 "패밀리"는 "고성능"루프에서 사용되므로 속도가 핵심입니다. 또한 특정 패밀리는 구성 파일에 의해 지정됩니다.구조적/패턴 C++보다 효율적인 방법이 있습니까?

문제는 주요 기능에 엄청난 코드 반복이 있다는 것입니다. 이 구조를 구성하는 더 좋은 방법이 있나요? HP<objx> testtest.loop(bobloblaw)을 세 번 쓸 필요는 없나요?

class obj1 { 
public: 
    double f(double x) const { return 1.; } 
}; 

class obj2 { 
public: 
    double f(double x) const { return x; } 
}; 

class obj3 { 
public: 
    double f(double x) const { return x*x; } 
}; 

template <class O> 
class HP { 
private: 
    O obj; 

public: 

    double loop(const vector<double>& x) { 
     double s = 0.; 
     for (auto i : x) s += obj.f(i); 

    return s; 
    } 
}; 

int main() { 
    string config = "bob"; 
    double result = 0; 
    vector<double> bobloblaw; 

    /* Read configuration file to determine which object to use. */ 
    if (config == "obj1") { 
     HP<obj1> test; 
     result = test.loop(bobloblaw); 
    } else if (config == "obj2") { 
     HP<obj2> test; 
     result = test.loop(bobloblaw); 
    } else if (config == "obj3") { 
     HP<obj3> test; 
     result = test.loop(bobloblaw); 
    } 

    return result; 
} 
+0

+1 볼 테 블로를위한 – JeremyFromEarth

+0

+1 체포 개발 용. –

답변

4

다음은 테스트되지 않은,하지만 작동합니다 : 유일하게 추가가 HP<>에 대한 기본 클래스와 코드의 if/else 논리를 대체하는지도입니다

class obj1 
{ 
public: 
    double f(double x) const { return 1.; } 
}; 

class obj2 
{ 
public: 
    double f(double x) const { return x; } 
}; 

class obj3 
{ 
public: 
    double f(double x) const { return x*x; } 
}; 

class HPbase 
{ 
public: 
    virtual double loop(const vector<double>&) = 0; 
}; 

template <class O> class HP: 
    public HPbase 
{ 
public: 
    double loop(const vector<double>& x) 
    { 
    double s = 0.; 
    for (auto i : x) 
     s += obj.f(i); 
    return s; 
    } 
private: 
    O obj; 
}; 

std::unordered_map<std::string, std::unique_ptr<HPbase>> decode{ 
    {"obj1"}, new HP<obj1>()}, 
    {"obj2"}, new HP<obj2>()}, 
    {"obj3"}, new HP<obj3>()} }; 

int main() 
{ 
    string config = "bob"; 
    double result = 0; 
    vector<double> bobloblaw; 

    /* Read configuration file to determine which object to use. */ 
    result = decode[config].loop(bobloblaw); 
} 

하는 것으로.

+0

감사합니다. 이것은 완벽하고 정확한 답변 유형입니다. – notrick

+0

왜 unordered_map입니까? std :: map을 사용하는 것이 더 좋고/빠르지 않습니까? –

+0

@DavidFeurle :이 경우 하나의 조회 만 있기 때문에 전혀 문제가되지 않을 수도 있습니다. 그러나 일반적으로'std :: map' 조회는 O (log n)이며,'std :: unordered_map' 조회는 O (1)입니다. 따라서 충분한 항목이 있으면'unordered_map '검색이 빨라집니다. 몇 가지 항목에 대해서는 어느 것이 더 빠르는지 (구현에 따라 다를 수도 있음) 모릅니다. 그러나 어쨌든 병목 현상이 발생하지는 않습니다. 그러나, 몇 가지 항목에 대해서,'std :: map'은 아마도 더 많은 메모리를 효율적으로 사용할 것입니다. – celtschk

3

같은 부모 승 /이 3 개 클래스의 모든 일 서브 클래스가 없습니다 (실제로,이 코드 덩어리 ...이보다 더 많은 라인이다)? main은 여전히 ​​올바른 하위 클래스를 사용하여 테스트에 할당해야하지만 테스트 자체는 공통 수퍼 클래스로 선언됩니다.

여기에 단점은 컴파일러가 test.loop 용 코드를 생성 할 때 모를 버전이 사용된다는 것입니다 (따라서 성능이 저하 될 수 있음). 따라서 런타임에 결정해야합니다.

이 문제를 해결할 수있는 대안은 공통 코드를 매크로로 작성하는 것이므로 한 번만 작성되지만 3 개의 개별 복사본으로 확장됩니다. 각 컴파일러는 다음과 같은 변형을 기반으로 최적화 할 수 있습니다. 테스트가 사용됩니다. 디버깅을 어리석게 만들 수는 있지만 성능에 초점을 맞추면 소스의 중복성이 줄어 듭니다.

+0

결정은 사용자 입력에 따라 다르므로 런타임에 항상 수행됩니다. –

+0

USED를 얻을 수있는 것은 런타임에 결정됩니다. 컴파일 타임에 각 버전에 대해 실행될 코드가 생성되므로 각 유형의 하위 클래스에 대한 코드 버전이 다르면 컴파일러는 각 버전을 더 잘 최적화 할 수 있습니다. –

+0

매크로를 사용하라는 제안에 +1이 있습니다. 위험에도 불구하고 유효한 용도가 있습니다. –

관련 문제