带有lambda的C++回调失败,返回bad_function_call

C++ callback with lambda fails with bad_function_call

本文关键字:bad 返回 function call 失败 lambda C++ 回调 带有      更新时间:2023-10-16

我稍微修改了[1]中的回调示例,将注册移到被调用者本身,如下所示。

// To build:
//   g++ -std=c++11 callback4.cpp
#include <stdio.h>
#include <functional>
//------------------------------------------------------------------------
// Callback function.
typedef std::function<int(int)> CallbackFunction;
//------------------------------------------------------------------------
// "Caller" allows a callback to be connected.  It will call that callback.
class Caller
{
  public:
    // Clients can connect their callback with this.
    void connectCallback(CallbackFunction cb)
    {
      printf("setting the callback..n");
      m_cb = cb;
      // This call works
      m_cb(10);
    }
    // Test the callback to make sure it works.
    void test()
    {
      printf("Caller::test() calling callback...n");
      int i = m_cb(10);
      printf("Result (50): %dn", i);
    }
private:
  // The callback provided by the client via connectCallback().
  CallbackFunction m_cb;
};
//------------------------------------------------------------------------
// "Callee" can provide a callback to Caller.
class Callee
{
  public:
    Callee(Caller c, int i) : m_i(i), caller(c) { }
    // The callback function that Caller will call.
    int callbackFunction(int i)
    {
      printf("  Callee::callbackFunction() inside callbackn");
      return m_i * i;
    }
    void registerCallback() {
      caller.connectCallback(
        [this](int i) { return this->callbackFunction(i); });
    }
private:
  // To prove "this" is indeed valid within callbackFunction().
  int m_i;
  Caller caller;
};
//------------------------------------------------------------------------
int main()
{
  Caller caller;
  Callee callee(caller, 5);
  callee.registerCallback();
  // Test the callback. This fails.
  caller.test();
  return 0;
}

在这里,我通过lambda表达式中的这个引用捕获Callee。但是在Caller中调用test()失败,在运行时抛出bad_function_call。但在注册时调用回调是有效的。知道为什么吗?输出如下。

正在设置回调
Callee::callbackFunction()内部回调
调用方::test()正在调用回调
在抛出"std::bad_function_call"的实例后调用terminate
what():bad_function_call

[1]http://tedfelix.com/software/c++-callbacks.html

让我们看看Callee构造函数:

Callee(Caller c, int i) : m_i(i), caller(c) { }

在这里,您通过值传递Caller,这意味着您复制对象。

因此,在main函数中,变量caller,而不是Callee::caller相同。main变量caller尚未注册任何回调。

简单的解决方案是使用参考:

class Callee
{
  public:
    Callee(Caller& c, int i) : m_i(i), caller(c) { }
    ...
  private:
    ...
    Caller& caller;
};

一个更好的解决方案可能是重新思考设计,以及你实际上试图解决的问题,以及用例。