• VC++中的std::function比较问题


    在VC++中,一个std::function对象会根据情况被编译成多种情况,函数指针,函数对象(lambda),其中还涉及了优化等问题。

    对于函数对象来说,常规的手段没有任何办法可以做比较,所以只能去二进制层面看看底层数据。

    在VC中可以用同一个结构去模拟std::function对象

    struct std_function_struct{

      // vtable[0] 与 vtable[1] 是相同的地址,其中是std::_Func_impl_no_alloc<模板参数...>::_Move地址 或者 std::_Func_impl_no_alloc<模板参数...>::_Copy地址

      // vtable[2] 中保存了 std::_Func_impl_no_alloc<模板参数...>::_Do_call 地址,这个地址是我们的判断依据。

          size_t* vtable;

      // 只有函数指针才会保存在这,哪怕lambda不能inline,其地址也会被直接静态编译到_Do_call中

          void* func_ptr; 

          // ... 其他信息对于我们的需求来说并不重要

    };

    如果是函数指针,很显然的指针就放在 func_ptr 中,比较就它就行。

    如果是lambda,我们可以比较vtable[2]是否相同

    vtable[2] 中存放的是 std::_Func_impl_no_alloc<模板参数...>::_Do_call() 地址

    根据模板参数的不同,哪怕是lambda,std::_Func_impl_no_alloc::_Do_call 也会编译成不同的代码。

    其中还涉及了优化问题,两段完全相同代码的lambda,会优化成同一段代码,这不就正好满足了我们需求的判断吗?

    但其中有一个比较遗憾的地方,std::function在保存lambda的对象时,func_ptr是不会初始化为0的。

    所以我们不能简单的先比较func_ptr再比较vtable[2],我们很大概率是需要先判断两个对象是否存在lambda,好在有std::function::target_type()可以满足我们的要求。

    最终代码如下:请注意,这段代码仅适用于VC++,并且不确定随着编译器更新是否能保持二进制一致性。

    template<typename _Ty>
    bool is_std_func_equal(_Ty& a, _Ty&b) {
        struct __std_func_struct {
            size_t* vt;
            void* func_ptr;
        };
        __std_func_struct* pa = (__std_func_struct*)&a;
        __std_func_struct* pb = (__std_func_struct*)&b;
    
        if (pa->func_ptr == pb->func_ptr) {
            // 如果func_ptr相等时,我们直接判断两个vtable[2]即可
            return (pa->vt[2] == pb->vt[2]);
        }
        else {
            // 只要func_ptr不相等,我们甭管它保存了什么,都先去类型信息中先查找<lambda_
            bool al = (strstr(a.target_type().name(), "<lambda_") != NULL);
            bool bl = (strstr(b.target_type().name(), "<lambda_") != NULL);
            if (al != bl) // 一个是lambda而另一个不是时,就不需要比较了
                return false;
    
            if (al) {
                // 两个都是lambda时,比较vtable[2]
                return (pa->vt[2] == pb->vt[2]);
            }
            else {
                // 两个都是函数指针时,比较func_ptr
                return (pa->func_ptr == pb->func_ptr);
            }
        }
    }
  • 相关阅读:
    JS--XML 操作
    JS--中的 Cookie 与存储
    php qr生成二维码
    jQuery cookie插件保存用户登陆信息
    linux BASH shell设置字体与背景颜色
    linux iostat命令详解 磁盘操作监控工具
    Nginx下10个安全问题提示
    PHP计算某个目录大小的方法
    php验证是否是md5编码的代码
    JS正则表达式获取字符串中特定字符
  • 原文地址:https://www.cnblogs.com/babypapa/p/16384946.html
Copyright © 2020-2023  润新知