• 欢迎浏览“String me = Creater\忠实的资深Linux玩家;”,请文明浏览,理性发言,有侵犯你的权益请邮件我(creater@vip.qq.com).
  • 把任何的失败都当作一次尝试,不要自卑;把所有的成功都想成是一种幸运,不要自傲。
  •    4年前 (2014-04-18)  boost.asio 评论关闭  9 
    文章评分 0 次,平均分 0.0

    在类的成员里有时候实现了异步操作,异步的回调函数仍为该类的成员函数,比如下面。

        async_write(m_socket, boost::asio::buffer(msg.c_str(), msg.size()),
            bind(&Games::HandSend, this,
                boost::asio::placeholders::error));

    上面这个例子是一个很常见的boost.asio的异步执行代码,如果没认真看很容易忽略了bind参数中的“this”参数,异步执行过程中另一个线程会持有这个"this"指针并在未知的时间里回调HandSend方法,而在持有这个指针的时间内,这个线程并不知道当前对象有可能已经被销毁,所以造成很低级的悬空指针。

    正确的做法应该是:

        async_write(m_socket, boost::asio::buffer(msg.c_str(), msg.size()),
            bind(&Games::HandSend, shared_from_this(),
                boost::asio::placeholders::error)
        );

    在asio中使用shared_from_this智能指针,该使用的时候必须使用,否则几乎肯定会发生问题。

    来分析分析什么时候该用this,什么使用该用shared_from_this()。

    1.使用this的地方举例

    1.1示例链接

    在主函数中定义了tcp_server对象,这个对象会一直存在栈中,而对于每次accept的连接,都是new出来的tcp_connection。

      void start_accept()
      {
        tcp_connection::pointer new_connection =
          tcp_connection::create(acceptor_.get_io_service());
    
        acceptor_.async_accept(new_connection->socket(),
            boost::bind(&tcp_server::handle_accept, this, new_connection,
              boost::asio::placeholders::error));
      }

    这里使用了一个工厂方法隐藏了new的代码,在bind中使用了this,因为tcp_server对象存在栈中,而且tcp_server对象并不是一个局部变量,不用担心他会在其他地方被释放掉。

    1.2示例链接

    server(boost::asio::io_service& io_service, short port)
        : io_service_(io_service),
          acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
      {
        session_ptr new_session(new session(io_service_));
        acceptor_.async_accept(new_session->socket(),
            boost::bind(&server::handle_accept, this, new_session,
              boost::asio::placeholders::error));
      }
    
      void handle_accept(session_ptr new_session,
          const boost::system::error_code& error)
      {
        if (!error)
        {
          new_session->start();
        }
    
        new_session.reset(new session(io_service_));
        acceptor_.async_accept(new_session->socket(),
            boost::bind(&server::handle_accept, this, new_session,
              boost::asio::placeholders::error));
      }

    类server中的两个函数和以上的解释一样。

    2.未使用this的地方,使用share_from_this举例

    以下的两个链接还是和上边两个链接分别相同,因为这两段程序中都使用了this与share_from_this,这能很好对比。

    2.1示例链接,与1.1对比

    void start()
      {
        message_ = make_daytime_string();
    
        boost::asio::async_write(socket_, boost::asio::buffer(message_),
            boost::bind(&tcp_connection::handle_write, shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred));
      }

    tcp_server的bind中使用了this,而这个tcp_connection中使用share_from_this(),因为这个cp_connection对象是存在堆中,被new出来的。

     2.2示例链接,与1.2对比

    void start()
      {
        using namespace std; // For time_t, time and ctime.
        time_t now = time(0);
        shared_const_buffer buffer(ctime(&now));
        boost::asio::async_write(socket_, buffer,
            boost::bind(&session::handle_write, shared_from_this()));
      }

    server的bind中使用了this,而这个session中使用share_from_this(),因为这个session对象是存在堆中,被new出来的。

    结论:

    1.如果对象是存在于栈中则必须使用this,否则出现bad_weak_ptr异常。
    2.如果对象存在于堆中则尽量使用share_from_this(),使用this的前提是你能保证这个对象一直存在(比如全局对象,主函数中具有全局生命的对象,静态对象)
     

    除特别注明外,本站所有文章均为String me = "Creater\忠实的资深Linux玩家";原创,转载请注明出处来自http://unix8.net/home.php/3324.html

    关于
    切换注册

    登录

    忘记密码 ?

    切换登录

    注册

    扫一扫二维码分享