简体   繁体   中英

C++ callback with lambda fails with bad_function_call

I slightly modified the callback example found at [1] to move the registration in to the callee itself as follows.

// 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): %d\n", 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 callback\n");
      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;
}

Here I capture the Callee by this reference in the lambda expression. But the call to test() to invoke within Caller failes throwing a bad_function_call at runtime. But calling the callback at registration time works. Any idea why that is? The output is given below.

setting the callback..
Callee::callbackFunction() inside callback
Caller::test() calling callback...
terminate called after throwing an instance of 'std::bad_function_call'
what(): bad_function_call

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

Lets take a look at the Callee constructor:

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

Here you pass Caller by value , meaning you copy the object.

So in the main function the variable caller is not the same as Callee::caller . The main variable caller have not had any callback registered.

The easy solution is to use references :

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

  private:
    ...
    Caller& caller;
};

A better solution might be to rethink the design, and what problem you are actually trying to solve, and about the use-cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM