【问题标题】:std::function callbacks with asynchronous operations带有异步操作的 std::function 回调
【发布时间】:2015-04-07 19:05:10
【问题描述】:

我想在包装类中使用 std::functions 作为回调参数。 该类包装了一个允许异步 TCP/IP 操作的库(实际上是 boost::asio,但 boost::asio 和 TCP/IP 在这里都不重要,只是它具有异步操作)。

库函数允许我传递另一个回调函数对象,该对象在请求的操作完成时被异步调用。 根据异步操作的结果,我想调用客户端指定的回调或开始进一步的操作。 下面的代码试图勾勒出我的意图。

using ConnectHandler = std::function<void(boost::system::error_code ec)>;

class MyConnection
{

public:

    void Connect(ConnectHandler handler);  // (1)
}

void MyConnection::Connect(ConnectHandler handler)
{
    SomeLibrary::async_connect(...,
        [handler](boost::system::error_code ec, ...) // (2)
        {
            //Depending on ec start a nested read/write operation.
            //One way or another it finally invokes the callback
            handler(ec); // (3)
        });
}

客户端代码如下所示

MyConnection conn;

conn.Connect([](boost::system::error_code ec)
{
    //check ec and start read/write operation
});

我的问题是: 在 (1) 中声明我的 Connect 方法的最佳方法是什么,f.e

void Connect(ConnectHandler handler);
void Connect(const ConnectHandler& handler);
void Connect(ConnectHandler&& handler);

根据这一点,我如何正确捕获 (2) 中的 lambda 捕获子句中的回调处理程序,以便我可以在 (3) 中调用它?

附注: 在所有异步操作完成之前,MyConnection 的客户端实例永远不会超出范围!

【问题讨论】:

  • 你有没有考虑过使用 boost.signals2,或者查看了它的注册回调接口?
  • 请注意,C++11 lambda 不能“通过移动捕获”(这已在 C++14 中引入)。根据async_connect,您可以通过使用支持将处理程序移动到函数对象中的手写函数对象类型来获得更好的性能。
  • [connectHandler] -- 我认为应该是[handler]?
  • 我还没有考虑过 boost.signals2 但会考虑的。关于 C++14:这很有趣,实际上我会欢迎带有 lambda init 捕获的 C++14,但目前我绑定到 VS2013 社区版并且似乎不支持 init 捕获。
  • @Yakk 谢谢,已编辑。

标签: c++ c++11 asynchronous callback std-function


【解决方案1】:

std::functionmove 便宜,所以按价值计算是可以接受的。使用&amp;&amp; 几乎毫无意义,因为充其量只是节省了move。并且它强制调用者move,而不是复制,也许调用者想要复制?

复制它们并不便宜,因此您可以考虑在可调用对象中通过move 捕获。

在 C++14 中,这很简单:

[handler=std::move(handler)]

作为捕获列表(广义捕获表达式)。

在 C++11 中,您需要编写一个自定义对象来执行此操作。

struct custom_work {
  ConnectHandler handler;
  void operator()(boost::system::error_code ec, ...) const {
    //Depending on ec start a nested read/write operation.
    //One way or another it finally invokes the callback
    handler(ec); // (3)
  }
};

然后

SomeLibrary::async_connect(...,
    some_work{std::move(handler)}
);

它的缺点是将代码从行内移到行外。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-27
    • 2017-05-30
    • 1970-01-01
    • 2016-01-16
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多