2016-10-14 4 views
0

Ich hatte die beiden Member-Funktionen von MyClass:Kann dieser Code ohne Laufzeitauswirkung faktorisiert werden?

Result MyClass::func1(const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam1& extraParam1) 
{ 
    Result result; 
    // prolog code, common to all, using commonParam1, commonParam2, commonParam3 
    doSomething(1, commonParam1, commonParam2, extraParam1); 
    // epilog code, common to all, using commonParam1, commonParam2, commonParam3 
    return result; 
} 

Result MyClass::func2(const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam2& extraParam2, const ExtraParam3& extraParam3) 
{ 
    Result result; 
    // prolog code, common to all, using commonParam1, commonParam2, commonParam3 
    doSomething(1, commonParam1, commonParam2, extraParam2, extraParam3); 
    // epilog code, common to all, using commonParam1, commonParam2, commonParam3 
    return result; 
} 

Ich muss das faktorisieren Duplizierung von prolog/Epilog-Code zu vermeiden, die für beide funktionieren genau gleich sind (wird modifiziert MyClass Attribute, Prologs erstellt verwendeten Variablen durch Epilog ... Zeug wie das). Der einzige Unterschied ist, dass eine andere Version von MyClass::doSomething aufgerufen wird (mit anderen Parametern). Als doSomething mit einem anderen Satz von Parametern aufgerufen wird, habe ich diesen Ansatz für Faktorisierung Vorlage und die Einführung eine Helfer-Klasse:

class helper1 
{ 
public: 
    helper1(const ExtraParam1& extraParam1) : extraParam1(extraParam1) {} 
    inline bool compute(MyClass& parent, const CommonParam& commonParam1, const CommonParam& commonParam2) const 
    { 
     return parent.doSomething(1, commonParam1, commonParam2, extraParam1); 
    } 

private: 
    const ExtraParam1& extraParam1; 
}; 

class helper2 
{ 
public: 
    helper2(const ExtraParam2& extraParam2, const ExtraParam3& extraParam3) : extraParam2(extraParam2), extraParam3(extraParam3) {} 
    inline bool compute(MyClass& parent, const CommonParam& commonParam1, const CommonParam& commonParam2) const 
    { 
     return parent.doSomething(1, commonParam1, commonParam2, extraParam2, extraParam3); 
    } 

private: 
    const ExtraParam2& extraParam2; 
    const ExtraParam3& extraParam3; 
}; 

template<typename Helper> 
inline Result funcT(MyClass& parent, 
        const CommonParam& commonParam1, 
        const CommonParam& commonParam2, 
        const CommonParam& commonParam3, 
        const Helper& helper) 
{ 
    // this function is a friend of MyClass, so prolog/epilog can use any private class attribute 

    Result result; 
    // prolog code, common to all, using commonParam1, commonParam2, commonParam3 
    helper.compute(parent, commonParam1, commonParam2); 
    // epilog code, common to all, using commonParam1, commonParam2, commonParam3 
    return result; 
} 

Result MyClass::func1(const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam1& extraParam1) 
{ 
    return funcT(*this, commonParam1, commonParam2, commonParam3, helper1(*this, extraParam1)); 
} 

Result MyClass::func2(const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam2& extraParam2, const ExtraParam3& extraParam3) 
{ 
    return funcT(*this, commonParam1, commonParam2, commonParam3, helper2(*this, extraParam2, extraParam3)); 
} 

Diese Funktionen sind Milliarden mal von unserem Algorithmus genannt, so muss das Refactoring hat die niedrigste Laufzeitauswirkung.

compute ist inline und alles wird als Referenz übergeben und ich verwendete Vorlage statt virtuelle Tabelle, um Laufzeitauswirkungen zu minimieren. Ich denke jedoch, dass dies zur Laufzeit Auswirkungen hat (zumindest erzeugen wir helper1, helper2 Objekte).

Hat mein Refactoring Auswirkungen auf die Laufzeit, die der Compiler nicht entfernen wird? Wenn ja, könnte jemand ein Refactoring mit geringerer Laufzeit vorschlagen?

Antwort

2

Hat mein Refactoring einen Laufzeiteinfluss, den der Compiler nicht entfernt? Wenn ja, könnte jemand ein Refactoring mit geringerer Laufzeit vorschlagen?

Der einzige Weg, um sicher zu sein, dass Sie nicht Overhead-Einführung ist messen. Profilieren Sie Ihren Code vor/nach dem Refactoring und überprüfen Sie die erzeugte Baugruppe .


Als Nachtrag, hier ist eine etwas einfachere Art und Weise Ihren Code Refactoring, die immer noch leicht für den Compiler Inline sein sollte. Stattdessen Verweise auf die zusätzlichen Parameter zu speichern, werden sie zu einem allgemeinen aufrufbar objekt perfekt weitergeleitet:

template <typename TF, typename... TExtraParams> 
Result MyClass::generic_func(const TF& doSomething, const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const TExtraParams&&... extraParams) 
{ 
    Result result; 
    // prolog code, common to all, using commonParam1, commonParam2, commonParam3 
    doSomething(1, commonParam1, commonParam2, std::forward<TExtraParams>(extraParams)...); 
    // epilog code, common to all, using commonParam1, commonParam2, commonParam3 
    return result; 
} 

Mit Ihrem aktuellen Design kann wie folgt verwendet werden:

generic_func([](
    const CommonParam& a, const CommonParam& b, const CommonParam& c, 
    const ExtraParam& extra0 
) 
{ 
    // ... will be called between prolog and epilog 
}, my_a, my_b, my_c, extra0); 
Verwandte Themen