【问题标题】:std::bind arguments not matching function parameters?std::bind 参数与函数参数不匹配?
【发布时间】:2021-07-24 07:45:13
【问题描述】:

我正在尝试通过连接握手传递一个套接字,并使用std::bind 这样做。我遇到的编译问题(在一个连续的块中,为了便于阅读,我添加了空格)是:

'std::_Bind<_Functor(_Bound_args ...)>::_Bind(_Functor&&, _Args&& ...) 

[with _Args = {socket_state**, std::function<void(socket_state*)>&, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor>&, boost::asio::io_context&}; 

_Functor = void (*)(socket_state*, std::function<void(socket_state*)>&, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp>&, boost::asio::io_context&); 

_Bound_args = {socket_state**, std::function<void(socket_state*)>, boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor>, boost::asio::io_context}]':

我的代码在下面,错误似乎在boost::asio::acceptor.async_accept(socket, ...)std::bind 参数和accept_new_client 方法的参数中唠叨

    void start_server(std::function<void(socket_state*)>& func, tcp::acceptor& acceptor, boost::asio::io_context& context)
    {
        acceptor.listen();
        // Start client connection loop
        networking::wait_for_client(func, acceptor, context);
    }

    void wait_for_client(std::function<void(socket_state*)>& func, tcp::acceptor& acceptor, boost::asio::io_context& context)
    {
        boost::asio::ip::tcp::socket socket(context);

        // socket_state is its own class which links a particular socket with an ID and buffer data
        // it also holds a function to indicate which part of the connection handshake it needs to go to next
        socket_state* state = new socket_state(func, &socket);
        acceptor.async_accept(socket, std::bind(&networking::accept_new_client, state, func, acceptor, context));
    }

    void accept_new_client(socket_state* state, std::function<void(socket_state*)>& func, tcp::acceptor& acceptor, boost::asio::io_context& context)
    {
            state->on_network_action(state);
            wait_for_client(func, acceptor, context);
    }

看起来它们会匹配,但您可以看到错误状态我的std::bind 参数是socket_state** 而不是socket_state*,以及boost::asio::basic_socket_acceptor&lt;boost::asio::ip::tcp, boost::asio::executor&gt;&amp; 而不是boost::asio::basic_socket_acceptor&lt;boost::asio::ip::tcp&gt;&amp;

我也不知道“with _Args”与“_Bound_args”是什么。

【问题讨论】:

  • 在堆上分配的结构中存储指向局部变量socket 的指针非常可疑。一旦wait_for_client 返回,该局部变量将被销毁,留下socket_state 一个悬空指针。
  • 错误消息表明您将socket_state**(两颗星)传递给std::bind,而您绑定的函数需要socket_state*(一颗星)。错误信息与显示的代码不匹配;它必须与您实际编译的代码不同。
  • 我很困惑,因为确切的代码 sn-p 是正在编译的。我对 sn-p 进行了更改(例如在一些 std::bind 参数后面添加 & )并且它更改了错误消息,因此它必须直接指向我正在编译的代码。也将存储智能指针而不是移动?
  • 准确完整的错误信息是什么?您只展示了其中的一部分 - 缺少的是编译器说出它认为错误的实际消息。我对boost::asio 不熟悉,但是quick glance 似乎暗示回调应该采用const boost::system::error_code&amp; error 参数;你的没有。也许这就是错误的根源。
  • @sehe networking 是一个命名空间,用作 server.cpp 类使用的抽象。 @IgorTandetnik 完整的错误是数百行;我发布的 sn-p 是第一部分,似乎可能是其他所有内容的根源。无论如何,现在在 sehe 的帮助下解决了。感谢您在这里的讨论,很有见地!

标签: c++ c++11 boost network-programming boost-asio


【解决方案1】:

这段代码有很多问题。

共享指针似乎处于错误的抽象级别。您会希望整个“连接”类型具有共享生命周期,而不仅仅是套接字。在您的情况下,socket_state 是一个不错的候选者。

无论如何,您的套接字是一个局部变量,您将一个过时的指针传递给 socket_state 内部。 Socket-state 看起来必然会被泄露。

所以这永远不会奏效。

接下来,绑定急切地绑定所有参数,留下一个空签名。这不是any overload 接受的[没有双关语]。你需要匹配

让我们去接受处理程序。另外,我们不要绑定所有冗余参数(func 已经在 socket_stateremember,io_context 被过度共享等)。

一般来说,您似乎需要培养对了解您所在州的位置的信心。例如。这条线是有症状的:

state->on_network_action(state);

由于on_network_actionsocket_state 的成员函数,因此永远不需要将state 作为参数传递(它将隐式传递为this)。在所有情况下,acceptorcontest 都是一样的。

演示

修复以上所有问题,使用 std::shared_ptr 和绑定(您已经这样做了),注意 placeholder::_1 接受错误代码等)

Live On Coliru

#include <boost/asio.hpp>
#include <memory>
#include <iostream>

namespace ba = boost::asio;
using namespace std::chrono_literals;
using boost::system::error_code;
using ba::ip::tcp;

struct socket_state;
using Callback = std::function<void(socket_state&)>;

struct socket_state : std::enable_shared_from_this<socket_state> {
    Callback _callback;
    tcp::socket _socket;

    template <typename Executor>
    socket_state(Callback cb, Executor ex) : _callback(cb)
                                           , _socket(ex)
    {
    }

    void on_network_action() {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

struct networking {
    using StatePtr = std::shared_ptr<socket_state>;

    explicit networking(ba::io_context& ctx, Callback callback)
        : context(ctx)
        , callback(callback)
    {
    }

    ba::io_context& context;
    tcp::acceptor acceptor {context, {{}, 8989}};
    Callback callback;

    void start_server()
    {
        std::cout << "start_server" << std::endl;
        acceptor.listen();
        wait_for_client(); // Start client connection loop
    }

    void stop_server() {
        std::cout << "stop_server" << std::endl;
        acceptor.cancel();
        acceptor.close();
    }

    void wait_for_client()
    {
        std::cout << "wait_for_client" << std::endl;
        // socket_state is its own class which links a particular socket with
        // an ID and buffer data it also holds a function to indicate which
        // part of the connection handshake it needs to go to next
        auto state =
            std::make_shared<socket_state>(callback, context.get_executor());

        acceptor.async_accept(state->_socket,
                              std::bind(&networking::accept_new_client, this,
                                        std::placeholders::_1, state));
    }

    void accept_new_client(error_code ec, StatePtr state)
    {
        if (ec) {
            std::cout << "accept_new_client " << ec.message() << std::endl;
            return;
        }
        std::cout << "accept_new_client " << state->_socket.remote_endpoint()
                  << std::endl;
        state->on_network_action();
        wait_for_client();
    }
};

int main() {
    ba::io_context ctx;
    networking server(ctx, [](socket_state&) {
        std::cout << "This is our callback" << std::endl;
    });

    server.start_server();

    ctx.run_for(5s);

    server.stop_server();
    ctx.run();
}

有一些随机连接:

start_server
wait_for_client
accept_new_client 127.0.0.1:54376
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54378
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54380
void socket_state::on_network_action()
wait_for_client
accept_new_client 127.0.0.1:54382
void socket_state::on_network_action()
wait_for_client
stop_server
accept_new_client Operation canceled

请注意,版本使 cmets

// socket_state is its own class which links a particular socket with
// an ID and buffer data it also holds a function to indicate which
// part of the connection handshake it needs to go to next

不再是完整的谎言:)

【讨论】:

  • 如果你已经做到了这一点,也许你会喜欢一个有一些明智的重命名的版本,而不是在Server 中硬编码端口,更一致的执行器使用,说明如何启动一个链每个会话:coliru.stacked-crooked.com/a/a2517741f7d28074
  • “总的来说,您似乎需要对了解自己所处的状态有信心” - 事实上,在我模糊地写下看起来不错的东西之前,我没有真正立足于我正在做的事情。感觉这个答案让我立足于实际看到我的 socket_state 和其他人(io_context 和接受器)发生了什么。感谢您清晰而彻底的回答。
猜你喜欢
  • 2019-01-18
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-30
  • 2020-08-28
  • 2021-09-26
相关资源
最近更新 更多