当 std::bind 遇上 this

背景

阅读公司之前项目的代码,看到一段代码如下:

        if (!m_api->SubFutureL1(
                m_config.config.symbol[0].future, std::bind(
                                                      &ArbitrageFc::OnSymbol1FutureMd, this,
                                                      std::placeholders::_1)))

其中,SubFutureL1 和 OnFutureL1MdFunc 的定义如下:

bool StrategyEngineImp::SubFutureL1(int64_t symbol, OnFutureL1MdFunc callback) {
  m_future_l1_callback[symbol] = callback;
  return m_mm.SubFuture(symbol);
}

typedef std::function<void(const FutureL1MarketData&)> OnFutureL1MdFunc; //std::function 下次再说

void OnSymbol1FutureMd(const FutureL1MarketData& md); //(类ArbitrageFc的成员函数)

对其中的 “bind + this” 的方式不够了解,查了之后,特做记录;

std::bind

由来

在c++98中,有std::bind1st和std::bind2nd,可以分别用来绑定func的2个参数,但使用并不友好;后来c++11中推出了std::bind,对之前的bind 1st和2nd有了本质的提升;参考C++11中的std::bind里的说法就是:
bind本身是一种延迟计算的思想,它本身可以绑定普通函数、全局函数、静态函数、类静态函数甚至是类成员函数

示例

咱们直接看具体的例子(也参考了上述链接):

#include <iostream>
#include <functional>
using namespace std;

int TestFunc(int a, char c, float f)
{
    cout << a << endl;
    cout << c << endl;
    cout << f << endl;

    return a;
}

int main()
{
    auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1);
    bindFunc1(10);

    cout << "=================================\n";
    //把TestFunc绑定到bindFunc2上,bindFunc2的第二个参数为TestFunc的第一个参数
    //bindFunc2的第一个参数为TestFunc的第二个参数,最后一个参数固定为100.1
    //类似于  TestFunc(bindFunc2's_var_2, bindFunc2's_var_1, 100.1);
    auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
    bindFunc2('B', 10);

    cout << "=================================\n";

    auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
    bindFunc3(100.1, 30, 'C');

    return 0;
}

用g++编译后执行,结果如下:
在这里插入图片描述
从上面的代码可以看到,bind能够在绑定时候就同时绑定一部分参数,未提供的参数则使用占位符表示,然后在运行时传入实际的参数值。PS:绑定的参数将会以值传递的方式传递给具体函数,占位符将会以引用传递。众所周知,静态成员函数其实可以看做是全局函数,而非静态成员函数则需要传递this指针作为第一个参数,所以std::bind能很容易地绑定成员函数。

理论联系实际

对于我的问题,比较有用的就是 非静态成员函数则需要传递this指针作为第一个参数
回答我遇到的问题:

m_api->SubFutureL1(
                m_config.config.symbol[0].future,
                std::bind(&ArbitrageFc::OnSymbol1FutureMd, this, std::placeholders::_1));

它可以拆解为如下:
1、bind相关:

OnFutureL1MdFunc callback = std::bind(&ArbitrageFc::OnSymbol1FutureMd, 
this, std::placeholders::_1)

最终等同于效果:

callback = this->OnSymbol1FutureMd(const FutureL1MarketData& var); 
//OnSymbol1FutureMd的第一个参数,就是callback 的第一个参数

在函数SubFutureL1实现了回调绑定,那么当有回调时,调用的就是:

OnSymbol1FutureMd(var);
//var就是“FutureL1MarketData& md”

而这个md是怎么来的呢?又涉及到了

// 期货行情
    while (m_mm.GetFutureL1Seq() > future_l1_seq) {
      auto md = m_mm.GetFutureL1Market(++future_l1_seq);
      if (md) {
        auto iter = m_future_l1_callback.find(md->symbol);
        if (iter != m_future_l1_callback.end()) {
          tlogi("期货行情")
            << utils::symbol::ToString(md->symbol) << " " << md->update_time
            << " " << md->bid_price[0] << " " << md->bid_volume[0]
            << " " << md->ask_price[0] << " " << md->ask_volume[0]
            << " " << md->last_price << " " << md->volume;
          iter->second(*md);
        }
      }
    }

其中的 iter->second(*md); 实现的就是这个的回调;

业务理解

大概说一下流程(这个是跟业务强相关的,并且也需要其他的代码上下文,估计是只能给自己做个记录):
1、在初始化里完成行情回调的绑定;初始化是从多层,两方面来完成的:

class StrategyEngineImp : public StrategyEngine–>
成员:market::MarketManager& m_mm–>
成员:
xytp::market::client::XyMarketClient* m_fm_master = nullptr; 和
xytp::market::client::XyMarketClientCallback* m_fm_master_cb = nullptr;
由于:
m_fm_master =
xytp::market::client::XyMarketClient::Create(m_config.future_master_lib.c_str());
并且
xytp::market::client::XyMarketClient* Create() {
return &market::redis::RedisMarketFuture::Instance();
}
所以:
m_fm_master 实际就是一个RedisMarketFuture的实例,在
MarketManager::InitMarket() 里调用了:m_fm_master->Init
也就是bool RedisMarketFuture::Init(const std::string& config)里:
m_redis->SetSubCallback(std::bind(
&RedisMarketFuture::OnPub,
this,
std::placeholders::_1,
std::placeholders::_2))
从而实现Pub的回调绑定:
所以当有行情到来时,行情网关先接收到?然后通过Redis发布,这时,StrategyEngineImp 里的成员:market::MarketManager& m_mm里的m_fm_master 和 m_fm_master_cb ,就会回调m_fm_master_cb ,也就是cb里的成员函数:OnFutureMarket,从而把传递的行情解析到m_fm_master_cb 里的成员MarketManager& m_mm 里的 market::FutureL1MarketData* future_md = m_mm.GetFutureL1Market(seq),
整体关系:
StrategyEngineImp–》market::MarketManager& m_mm;–》FutureMarketCallback–》m_mm(MarketManager::Instance())–》market::FutureL1MarketData* future_md = m_mm.GetFutureL1Market(seq);
上述2个类里的成员m_mm实际上指向的是同一个对象实例【market::MarketManager::Instance()】

2、在StrategyTradingEngine::MainThread里,当有行情到来时,会根据seq来判断得知,然后从之前的回调绑定里,拿到最新的行情,然后通过 iter->second(*md); 来实现行情驱动

更多学习参考

C++11中的std::bind
C++11中的std::function

  • 15
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lqw198421

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值