【问题标题】:c++: Performance increase on non-template delegate classc++:非模板委托类的性能提升
【发布时间】:2014-05-06 04:08:20
【问题描述】:

这是一个简单的委托类,仅适用于格式为 void ClassType::MethodType( InputType& ) 的方法,但可以轻松扩展为更通用的函数,只是因为它太大而未显示。

class Delegate
{
public:
    Delegate( void ) : Object( NULL ), Argument( NULL ) { }
    virtual ~Delegate( void ) { }

    template <class ClassType, class InputType, void (ClassType::*MethodType)( InputType )>
    void Create( ClassType* SetObject, void* SetArgument = NULL )
    {
        Object = SetObject;
        Argument = SetArgument;
        StaticCall = &CallMethod<ClassType, InputType, MethodType>;
    }

    template <class InputType>
    inline void operator()( InputType InputValue ) const
    {
        (*StaticCall)( Object, static_cast<void*>(InputValue) );
    }

    inline void operator()( void ) const
    {
        (*StaticCall)( Object, Argument );
    }

protected:
    typedef void (*FunctionCallType)( void*, void* );

    void* Object;
    void* Argument;
    FunctionCallType StaticCall;

private:
    template <class ClassType, class InputType, void (ClassType::*MethodType)( InputType )>
    static inline void CallMethod( void* SetObject, void* PassArgument )
    {
        (static_cast<ClassType*>( SetObject )->*MethodType)( static_cast<InputType>(PassArgument) );
    }
};

它很灵活,可用于池化回调类,但我遇到的一个问题是,到目前为止,它与虚拟调用相比(在我计划的大型向量中使用时甚至更慢),如果它被使用作为基类。我正在寻找有关如何提高性能的任何建议,因为我没有想法,即使它会影响功能。

我使用的最简单的性能测量代码(使用 -O3)是:

class VirtualBase
{
public: 
    virtual void TestCall( int* Data ) {}
};

class VirtualTest : public VirtualBase
{
public:
    VirtualTest() : Value(0) {}

    void TestCall( int* Data )
    {
        Value += *Data;
    }
private:
    int Value;
};


class DelTest : public Delegate
{
public:
    DelTest() : Value(0)
    {
        Create<DelTest, int*, &DelTest::TestCall>( this );
    }

    void TestCall( int* Data )
    {
        Value += *Data;
    }
private:
    int Value;
};

int main( int argc, char **argv )
{
    clock_t start;
    int Value = 1;

    VirtualBase* NewBase = new VirtualTest;

    start = clock();
    for( size_t Index = 0; Index < 1000000000; ++Index )
    {
        NewBase->TestCall( &Value );
    }
    delete NewBase;
    std::cout << (( std::clock() - start ) / (double)CLOCKS_PER_SEC) << std::endl;


    Delegate* NewDBase = new DelTest;
    start = clock();
    for( size_t Index = 0; Index < 1000000000; ++Index )
    {
        NewDBase->operator()( &Value );
    }
    delete NewDBase;
    std::cout << (( std::clock() - start ) / (double)CLOCKS_PER_SEC) << std::endl;

    return 0;
}

我应该提到,我希望类保持非模板,因为它使类使用回调到任何易于在单个向量中迭代的东西。

【问题讨论】:

  • 你检查过The Impossibly Fast C++ Delegates吗?它与您的非常相似,但一个区别是成员函数指针是编译时常量,因此您不需要将其作为运行时参数传递。
  • 我会删除Argument。这是std::bind 的工作,在一个类中混合两种不同的功能并不是一个好的设计——委托本身就足够复杂。此外,对于一般情况,C++11 中的可变参数实现不会比您的 1 参数版本长很多。
  • 你试过 std::function 了吗?

标签: c++ casting delegates


【解决方案1】:

您可能想看看这篇关于 CodeProject 的 Lightweight Generic C++ Callbacks 文章

链接文章中的一些代码,展示了使用函数模板进行转发:

template<typename R, typename P1, typename P2>
class Callback
{
public:
    typedef R (*FuncType)(void*, P1, P2);
    Callback() : func(0), obj(0) {}
    Callback(FuncType f, void* o) : func(f), obj(o) {}
    R operator()(P1 a1, P2 a2)
    {
        return (*func)(obj, a1, a2);
    }

private:
    FuncType func;
    void* obj;
};

template<typename R, class T, typename P1, typename P2, R (T::*Func)(P1, P2)>
R Wrapper(void* o, P1 a1, P2 a2)
{
    return (static_cast<T*>(o)->*Func)(a1, a2);
}

class Foo
{
public:
    float Average(int n1, int n2)
    {
        return (n1 + n2) / 2.0f;
    }
};

float Calculate(int n1, int n2, Callback<float, int, int> callback)
{
    return callback(n1, n2);
}

int main()
{
    Foo f;
    Callback<float, int, int> cb         
        (&Wrapper<float, Foo, int, int, &Foo::Average>, &f);
    float result = Calculate(50, 100, cb);
    // result == 75.0f
    return 0;
}

在 stackoverflow here 上还有一篇很棒的文章,它将为您提供更好的见解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 2017-10-08
    • 2015-10-29
    • 1970-01-01
    相关资源
    最近更新 更多