这段代码可以分解而没有运行时影响吗?

时间:2016-10-14 08:37:06

标签: c++ refactoring

我有MyClass的两个成员函数:

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;
}

我需要对此进行分解以避免重复prolog / epilog代码,这两个函数完全相同(修改MyClass属性,prolog创建epilog使用的变量......这样的东西)。唯一的区别是调用了不同版本的MyClass::doSomething(具有不同的参数)。当使用不同的参数集调用doSomething时,我使用此方法使用模板进行分解并引入辅助类:

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 ) );
}

我们的算法会将这些函数调用数十亿次,因此重构必须具有最低的运行时影响。

computeinline,所有内容都通过引用传递,我使用模板而不是虚拟表来最小化运行时影响。但是,我想这会在运行时产生影响(至少我们会创建helper1helper2个对象。

我的重构是否会影响编译器不会删除的运行时影响? 如果是的话,是否有人可以提出具有较低运行时影响的重构?

1 个答案:

答案 0 :(得分:2)

  

我的重构是否会影响编译器不会删除的运行时影响?如果是的话,是否有人可以提出具有较低运行时影响的重构?

确保您不会引入开销的唯一方法是衡量。在重构之前/之后配置代码并检查生成的程序集

作为附录,这里有一种稍微简单的重构代码的方法,编译器内联仍然很容易。它们不是存储对额外参数的引用,而是完美地转发到通用可调用对象:

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;
}

根据您当前的设计,可以按如下方式使用:

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);