C++ std::bind函数用法

1、绑定到基本函数

auto bound_function = std::bind(original_function, arg1, arg2, ..., placeholder);

original_function是绑定的原始函数或者成员函数指针,也可以是一个可调用对象(lamda表达式)
arg1, arg2, ...是要绑定的参数,可以是实际的值,也可以是占位符(std::placeholders::_1),表示调用新函数对象时需要提供的参数位置。

2、绑定到成员函数

#include <functional>
#include <iostream>

class MyClass {
public:
    void display(int value) {
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    MyClass obj;
    auto bound_display = std::bind(&MyClass::display, &obj, std::placeholders::_1);
    bound_display(42); // 输出 Value: 42
    return 0;
}

&MyClass::display获取成员函数地址,&obj指定调用该函数的实例。

看一个例子解释用法:

TcpServer类的构造函数中定义:
acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this,
        std::placeholders::_1, std::placeholders::_2));

// 有一个新的客户端的连接,acceptor会执行这一个回调
void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)//有新连接来了
{   
    //轮询算法,选择一个subLoop,来管理channel
    EventLoop *ioLoop = threadPool_->getNextLoop(); 
    ......
}

this 指针: 在类的成员函数中,this 是一个指向当前对象的指针。它用于访问该对象的成员变量成员函数
std::bind: 这个函数模板允许将一个成员函数特定的对象进行绑定,从而可以创建一个可调用对象std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2) 创建了一个可调用对象,它将调用当前 TcpServer 对象(由 this 指向)的 newConnection 函数,并将 std::placeholders::_1 和 std::placeholders::_2 作为参数传递给它。

调用的时候,会传参:

newConnectionCallback_(connfd, peerAddr);

3、绑定到std::function

std::function是一个通用的函数封装器 ,它可以存储任何可调用对象,并允许我们以后以统一的方式调用它们。我们可以将std::bind的结果存储到std::function中,以提高代码灵活性和可读性。

#include <functional>
#include <iostream>

int multiply(int a, int b) {
    return a * b;
}

int main() {
    std::function<int(int)> double_it = std::bind(multiply, 2, std::placeholders::_1);
    std::cout << double_it(5) << std::endl; // 输出10
    return 0;
}

看一个例子解释用法:
1、EventLoop.cc
开启事件循环,处理发生事件的channel,调用handleEvent函数:

 for (Channel *channel : activeChannels_)
 {
     //Poller能监听哪些channel发生事件了,然后上报给EventLoop,EventLoop通知channel处理相应的事件
     channel->handleEvent(pollReturnTime_);//事先已经绑定好
 }

2、Channel.cc
传入的参数是Timestamp,判断当前channel和Tcpconnection对象是否还处于绑定状态,然后执行handleEventWithGuard函数,再执行readCallback_回调函数。

//fd得到poller通知后,处理事件的函数
void Channel::handleEvent(Timestamp receiveTime)
{
    if (tied_) // 如果绑定
    {
        std::shared_ptr<void> guard = tie_.lock(); // .lock() 智能指针的提升操作  弱->强
        if (guard) // 提升成功才执行,否则说明与tie_绑定的对象已经销毁,就忽略事件处理
        {
            handleEventWithGuard(receiveTime);
        }
    }else { // 没绑定
        handleEventWithGuard(receiveTime);
    }
}

// 根据poller通知的channel发生的具体事件,由channel负责具体调用的回调操作
void Channel::handleEventWithGuard(Timestamp receiveTime)
{   
    LOG_INFO("channel handleEvent revents:%d", revents_);

    // read
    if (revents_ & (EPOLLIN | EPOLLPRI))
    {
        if (readCallback_)
        {
            readCallback_(receiveTime);
        }
    }
    ...
}

3、TcpConnection.cc
在TcpConnection对象创建时(构造函数中),就已经将handleRead函数绑定到对应channel中的readCallback_上了,使用的是move移动转发+bind绑定器+function函数封装器,相当于如下操作:

std::function<void(Timestamp)> readCallback_ = std::move(std::bind(&TcpConnection::handleRead, this, std::placeholders::_1) 

调用位置为 readCallback_(receiveTime); 一个占位符,传入receiveTime,执行handleRead函数,完成读取数据的操作。

// 下面给channel设置相应的回调函数,poller给channel通知感兴趣的事件发生了,channel会回调相应的操作函数
channel_->setReadCallback(
    std::bind(&TcpConnection::handleRead, this, std::placeholders::_1)
);
...
//表示fd有数据可读
void TcpConnection::handleRead(Timestamp receiveTime)
{
    int savedErrno = 0;
    ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);
    if (n > 0) 
    {
        // 已建立连接的用户,有可读事件发生了,调用用户传入的回调操作 onMessage
        // shared_from_this: 获取当前TcpConnection对象的一个智能指针 TcpConnectionPtr
        messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);
    }
    else if (n == 0)
    {
        handleClose();
    }
    else
    {
        errno = savedErrno;
        LOG_ERROR("TcpConnection::handleRead error! ");
        handleError();
    }
}

4、Channel.h

    // 不用typedef,而用using定义类型
    using ReadEventCallback = std::function<void(Timestamp)>; // 只读事件回调
	ReadEventCallback readCallback_;
	
    // set是为了 设置(相当于赋值操作) 回调函数对象  提供 <对外的接口>  (EventLoop、TcpConnection中会进行设置)
    // cb是一个函数对象,存在值和地址,直接使用会导致资源复制,这里直使用std::move移动语义避免不必要的复制和提高性能
    // 将cb标记为右值引用,在调用对象的移动构造函数或移动赋值运算符完成实际移动操作。
    void setReadCallback(ReadEventCallback cb) { readCallback_ = std::move(cb); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值