0

I am currently expiriencing a "bad function call" error in my code that I am not able to solve. Apparently the callback that I pass by const reference to the TcpConnection is null/not valid anymore when the TcpConnection::start() method is called.

For simplicitly, I posted a reduced minimal example below that does not contain the full code. If this is not enough to track down the problem I can edit my question and post the rest of the code as well.

I am by far no C++ expert so be patient with me :)

typedef std::function<void()> TcpMessageCallback;

class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
public:
    typedef std::shared_ptr<TcpConnection> pointer;

    static pointer create(boost::asio::io_context &io_context, const TcpMessageCallback &cb) {
        return pointer(new TcpConnection(io_context, cb));
    }

    tcp::socket &socket() {
        return socket_;
    }

    void start() {
        onDataCallback(); // <---- ***Error happens here***
    }

private:
    TcpConnection(boost::asio::io_context &io_context, const TcpMessageCallback &cb)
    : socket_(io_context), onDataCallback(cb){};

    tcp::socket socket_;
    const TcpMessageCallback &onDataCallback;
};

class TcpServer {
public:
    explicit TcpServer(boost::asio::io_context &context, const TcpMessageCallback &cb) :
            io_context(context),
            acceptor(context, tcp::endpoint(tcp::v4(), TCP_PORT_NUMBER)),
            onDataReceivedCb(cb) {
        start_accept();
    }

private:
    void start_accept() {
        tcpConnection = TcpConnection::create(io_context, onDataReceivedCb);

        auto onAcceptCb = [objPtr = this](auto error) {
                    objPtr->handle_accept(error);
                };
        acceptor.async_accept(tcpConnection->socket(), onAcceptCb);
    }

    void handle_accept(const boost::system::error_code &error) {
        if (!acceptor.is_open())
        {
            return;
        }

        if (!error) {
            tcpConnection->start();
        }
        start_accept();
    }

    boost::asio::io_context &io_context;
    tcp::acceptor acceptor;
    TcpConnection::pointer tcpConnection;
    const TcpMessageCallback &onDataReceivedCb;
};

And then I would use it by starting the TcpServer with my own passed lambda function.

//... define context
auto server = TcpServer(io_context, []{ /*...*/});
io_context.run()

However when a new connection arrives the error happens at the TcpConnection::start() already where the onDataReceived callback somehow does not have a (or has an deleted?) function reference. It works when I pass the callback by value.

What could be the reason for this and how do I solve it?

  • 1) "_It works when I pass the callback by value._" "_how do I solve it?_" Answer seems obvious here. 2) "_What could be the reason for this_" Do you know what is the difference between passing variables by reference, and by value? – Algirdas Preidžius Oct 01 '20 at 16:15
  • I am not sure if this would be the best way of solving it. Since passing it by value would lead to unnecessary memory copy, I guess? Is there no way of solving it with a reference? – Marcel_marcel1991 Oct 01 '20 at 16:17
  • Do you know the difference between the variables, that contain the value, and references? And extra requirements imposed on references, so that they can be used, without invoking undefined behavior? Releated reading: [Should I pass an std::function by const-reference?](https://stackoverflow.com/questions/18365532/should-i-pass-an-stdfunction-by-const-reference) – Algirdas Preidžius Oct 01 '20 at 16:41

0 Answers0