高性能仿函数(FixedFunction)-替代std中的function

原文转自:http://www.tanjp.com (即时修正和更新)

 

固定大小仿函数(FixedFunction)

仿函数是C++很多新特性的基础,如 lambda表达式。但是STL提供的std::function兼顾了太多情况,性能不高。于是做了优化,实现代码如下:

template <typename SIGNATURE, size_t STORAGE_SIZE = 128>
class FixedFunction;
template <typename R, typename... ARGS, size_t STORAGE_SIZE>
class FixedFunction<R(ARGS...), STORAGE_SIZE>
{
    typedef R (*FuncPtrType)(ARGS...);
    	typedef R(*MethodType)(void* object_ptr, FuncPtrType free_func_ptr, ARGS... args);
    	typedef void(*AllocType)(void* storage_ptr, void* object_ptr);
public:
    FixedFunction() : mf_function_ptr(nullptr), mf_method_ptr(nullptr), mf_alloc_ptr(nullptr) {}
  
    template <typename FUNC>
    FixedFunction(FUNC&& object) : FixedFunction()
    {
        typedef typename std::remove_reference<FUNC>::type unref_type;
        static_assert(sizeof(unref_type) < STORAGE_SIZE, "functional object doesn't fit into internal storage");
        static_assert(std::is_move_constructible<unref_type>::value, "Should be of movable type");
        mf_method_ptr = [](void* object_ptr, FuncPtrType, ARGS... args) -> R
        {
            return static_cast<unref_type*>(object_ptr)->operator()(args...);
        };
        mf_alloc_ptr = [](void* storage_ptr, void* object_ptr)
        {
            if(object_ptr)
            {
                unref_type* x_object = static_cast<unref_type*>(object_ptr);
                new(storage_ptr) unref_type(std::move(*x_object));
            }
            else
            {
                static_cast<unref_type*>(storage_ptr)->~unref_type();
            }
        };
        mf_alloc_ptr(&ms_storage, &object);
    }
    template <typename RET, typename... PARAMS>
    FixedFunction(RET (*func_ptr)(PARAMS...)) : FixedFunction()
    {
        mf_function_ptr = func_ptr;
        mf_method_ptr = [](void*, FuncPtrType f_ptr, ARGS... args) -> R
        {
            return static_cast<RET (*)(PARAMS...)>(f_ptr)(args...);
        };
    }
    FixedFunction(FixedFunction&& o) : FixedFunction()
    {
        move_from_other(o);
    }
    FixedFunction& operator=(FixedFunction&& o)
    {
        move_from_other(o);
        return *this;
    }
    ~FixedFunction()
    {
        if(mf_alloc_ptr) mf_alloc_ptr(&ms_storage, nullptr);
    }
    R operator()(ARGS... args)
    {
        if(!mf_method_ptr) throw std::runtime_error("call of empty functor");
        return mf_method_ptr(&ms_storage, mf_function_ptr, args...);
    }

private:
	// 不可拷贝
    FixedFunction& operator=(const FixedFunction&) = delete;
    FixedFunction(const FixedFunction&) = delete;

    void move_from_other(FixedFunction& o)
    {
        if(this == &o) return;
        if(mf_alloc_ptr)
        {
            mf_alloc_ptr(&ms_storage, nullptr);
            mf_alloc_ptr = nullptr;
        }
        else
        {
            mf_function_ptr = nullptr;
        }
        mf_method_ptr = o.mf_method_ptr;
        o.mf_method_ptr = nullptr;
        if(o.mf_alloc_ptr)
        {
            mf_alloc_ptr = o.mf_alloc_ptr;
            mf_alloc_ptr(&ms_storage, &o.ms_storage);
        }
        else
        {
            mf_function_ptr = o.mf_function_ptr;
        }
    }
private:
	union
	{
		typename std::aligned_storage<STORAGE_SIZE, sizeof(size_t)>::type ms_storage;
		FuncPtrType mf_function_ptr;
	};
	MethodType mf_method_ptr;
	AllocType mf_alloc_ptr;
};

 

性能测试示例

 

void test1_func()
{
    	std::string s;
    	for (uint32 i = 0; i < 10; ++i)
    	{
    		s.append(1, (char)i);
    	}
    	s.reserve();
}

// 函数直接调用 
for (uint32 i = 0; i < 2000000; ++i)
{
    test_func(); 
}

// std::function包装并调用
std::function<void()> f;
for (uint32 i = 0; i < 2000000; ++i)
{
    f = std::move(std::bind(&test_func));
    f();
}

// FixedFunction包装并调用
FixedFunction<void(), 128> ff;
for (uint32 i = 0; i < 2000000; ++i)
{
    test_func(); 
    ff = std::move(std::bind(&test_func));
    ff();
}

 

结果

执行 函数2000000次

C++函数直接调用耗时(毫秒) :12032

std::function包装调用耗时(毫秒) : 20632

FixedFunction包装调用耗时(毫秒):13442

 

优化效果明显,FixedFunction调用的性能接近C++直接函数调用

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 `std::function` 封装类成员函数时,需要将类对象的指针或引用也一并封装到 `std::function` 对象。具体做法是在 `std::function` 类型的模板参数,将类对象的指针或引用作为第一个参数,函数签名作为第二个参数。 示例如下: ```c++ #include <iostream> #include <functional> class Foo { public: void func(int x, int y) { std::cout << x + y << std::endl; } }; int main() { Foo foo; std::function<void(Foo*, int, int)> f = &Foo::func; // 将成员函数封装到 std::function 对象 f(&foo, 1, 2); // 调用成员函数 return 0; } ``` 上述代码,`std::function<void(Foo*, int, int)>` 表示一个接受三个参数,第一个参数是 `Foo*` 类型的指针或引用,第二个和第三个参数是 int 类型的可调用对象。`f` 对象封装了 `Foo` 类的成员函数 `func`,可以通过 `f` 对象调用该成员函数。在调用时,需要先传入类对象的指针或引用,再传入成员函数的参数。 需要注意的是,如果成员函数是 const 成员函数,则需要将 `std::function` 的模板参数改为 `void (Foo::*)(int, int) const`。同时,在创建 `std::function` 对象时,需要使用 `std::mem_fn` 函数将成员函数转换为函数对象。示例如下: ```c++ #include <iostream> #include <functional> class Foo { public: void func(int x, int y) const { std::cout << x + y << std::endl; } }; int main() { Foo foo; std::function<void(const Foo*, int, int)> f = std::mem_fn(&Foo::func); // 将 const 成员函数封装到 std::function 对象 f(&foo, 1, 2); // 调用 const 成员函数 return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值