`
monkeycn
  • 浏览: 43796 次
  • 性别: Icon_minigender_1
  • 来自: 福州
文章分类
社区版块
存档分类
最新评论

Boost 库 Enable_shared_from_this 实现原理分析

 
阅读更多

使用情景:当类对象被 shared_ptr 管理时,需要在类自己定义的函数里把当前类对象作为参数传给其他函数时,这时需要传递一个 shared_ptr ,否则就不能保持 shared_ptr 管理这个类对象的语义(因为有一个 raw pointer 指向这个类对象,而 shared_ptr 对类对象的这个引用没有计数,很有可能 shared_ptr 已经把类对象资源释放了,而那个调用函数还在使用类对象——显然,这肯定会产生错误)。

很好奇这个模板类的实现。

先看看怎么使用:

对一个类 A ,当我们希望使用 shared_ptr 来管理其类对象时,而且需要在自己定义的函数里把类对象 shared_ptr (为什么不用普通指针,当我们使用智能指针管理资源时,必须统一使用智能指针,而不能在某些地方使用智能指针某些地方使用 raw pointer ,否则不能保持智能指针的语义,从而产生各种错误)传给其他函数时,可以让类 A 从 enable_shared_from_this 继承:

class A : public boost::enable_shared_from_this<A> {
};

然后在类 A 中需要传递类对象本身 shared_ptr 的地方使用 shared_from_this 函数来获得指向自身的 shared_ptr 。

一个非常有代表性的例子:

http://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html

另《Beyond the C++ Standard Library》 shared_ptr 节也有很简单明了的例子。

实现原理:

首先要考虑的是:在类对象本身当中不能存储类对象本身的 shared_ptr ,否则类对象 shared_ptr 永远也不会为0了,从而这些资源永远不会释放,除非程序结束。

其次:类对象肯定是外部函数通过某种机制分配的,而且一经分配立即交给 shared_ptr 管理(再次强调一遍:给 shared_ptr 管理的资源必须在分配时交给 shared_ptr ),而且以后凡是需要共享使用类对象的地方必须使用这个 shared_ptr 当作右值来构造产生或者拷贝产生另一个 shared_ptr 从而达到共享使用的目的。

有了以上两点的限制,要实现我们的目标(即在类对象内部使用类对象的 shared_ptr )有以下两种方案:

1、类对象的外部 shared_ptr 作为函数参数传给类的需要引用类对象自身的函数——显然,这种方法很丑陋,而且并不是所有的情况都可行(如在外部 shared_ptr 不可见的作用域中就不行);

2、类对象自身存储某种信息,在需要自身 shared_ptr 时来产生一个临时的 shared_ptr 。

显然,第2种方法更优雅(对于用户来说),关键是信息怎么存储?

对了, weak_ptr !

实际上, boost 中就是这样实现的。

但现在的问题是:何时初始化这个 weak_ptr ?因为类对象生成时还没有生成相应的用来管理这个对象的 shared_ptr 。

boost 1.39.0 中是这样实现的:

首先生成类 A :会依次调用 enable_shared_from_this 的构造函数(定义为 protected ),以及类 A 的构造函数。在调用 enable_shared_from_this 的构造函数时,会初始化定义在 enable_shared_from_this 中的 weak_ptr (调用其默认构造函数),这时这个 weak_ptr 是无效的(或者说不指向任何对象)。

接着:外部程序会把指向类 A 对象的指针作为初始化参数来初始化一个 shared_ptr 。

现在来看看 shared_ptr 是如何初始化的, shared_ptr 定义了如下构造函数:

template<class Y>
    explicit shared_ptr( Y * p ): px( p ), pn( p )
    {
        boost::detail::sp_enable_shared_from_this( this, p, p );
    }

里面调用了  boost::detail::sp_enable_shared_from_this :

template< class X, class Y, class T >
inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx,
Y const * py, boost::enable_shared_from_this< T > const * pe )
{
    if( pe != 0 )
    {
        pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
    }
}

里面又调用了 enable_shared_from_this 的 _internal_accept_owner :

template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
    {
        if( weak_this_.expired() )
        {
            weak_this_ = shared_ptr<T>( *ppx, py );
        }
    }

而在这里对 enable_shared_from_this 的成员 weak_ptr 进行拷贝赋值,使得整个 weak_ptr 作为类对象  shared_ptr 的一个观察者。

这时,当类对象本身需要自身的 shared_ptr 时,就可以从这个 weak_ptr 来生成一个了。

//
// server.cpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

std::string make_daytime_string()
{
  using namespace std; // For time_t, time and ctime;
  time_t now = time(0);
  return ctime(&now);
}

class tcp_connection
  : public boost::enable_shared_from_this<tcp_connection>
{
public:
  typedef boost::shared_ptr<tcp_connection> pointer;

  static pointer create(boost::asio::io_service& io_service)
  {
    return pointer(new tcp_connection(io_service));
  }

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

  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));
  }

private:
  tcp_connection(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

  void handle_write(const boost::system::error_code& /*error*/,
      size_t /*bytes_transferred*/)
  {
  }

  tcp::socket socket_;
  std::string message_;
};

class tcp_server
{
public:
  tcp_server(boost::asio::io_service& io_service)
    : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
  {
    start_accept();
  }

private:
  void start_accept()
  {
    tcp_connection::pointer new_connection =
      tcp_connection::create(acceptor_.io_service());

    acceptor_.async_accept(new_connection->socket(),
        boost::bind(&tcp_server::handle_accept, this, new_connection,
          boost::asio::placeholders::error));
  }

  void handle_accept(tcp_connection::pointer new_connection,
      const boost::system::error_code& error)
  {
    if (!error)
    {
      new_connection->start();
      start_accept();
    }
  }

  tcp::acceptor acceptor_;
};

int main()
{
  try
  {
    boost::asio::io_service io_service;
    tcp_server server(io_service);
    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }

  return 0;
}
分享到:
评论

相关推荐

    C++ Boost程序库boost_1_35_0

    C++ Boost程序库boost_1_35_0C++ Boost程序库boost_1_35_0C++ Boost程序库boost_1_35_0C++ Boost程序库boost_1_35_0C++ Boost程序库boost_1_35_0C++ Boost程序库boost_1_35_0C++ Boost程序库boost_1_35_0

    boost_1_74_0.zip

    标题中的"boost_1_74_0.zip"表明这是一个Boost库的特定版本,即1.74.0版。这个版本的Boost是为Visual Studio 2019 (vc142)编译器优化的,包含了适用于x86和x64两种架构的编译版本。 在C++编程中,Boost库是一个极其...

    boost_1_59_0.tar

    boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_0.tar.zip boost_1_59_...

    boost_1_78_0编译及使用

    在本文中,我们将详细讨论如何编译和使用Boost_1_78_0版本。 首先,你需要下载Boost的1.78.0版本,这可以通过访问Boost的官方网站完成。下载完成后,你会得到一个名为`boost_1_78_0`的压缩文件,解压到你的工作目录...

    boost_1_44_0

    "boost_1_44_0"是Boost库的一个特定版本,发布于2010年,包含了Boost库在那个时间点的所有组件和功能。 Boost库的创建初衷是为了补充C++标准库的不足,提供更先进的数据结构、算法、工具和编程模式。它不仅被C++...

    boost_pi_control_loop_design.rar_boost mathcad_boost pi_boost闭环

    本资料"boost_pi_control_loop_design.rar"聚焦于Boost电路的PI(比例积分)控制器设计,旨在实现稳定的闭环控制系统。Mathcad是一款强大的工程计算软件,它结合了数学计算、可视化和文档编写功能,是进行此类分析的...

    boost_1_59_0.tar.gz

    这个名为"boost_1_59_0.tar.gz"的压缩包文件,是Boost库的一个特定版本,即1.59.0版。这个版本在发布时是一个流行的选择,因为它引入了许多新特性并修复了一些已知问题,为开发者提供了更稳定的开发环境。 Boost库...

    boost_1_53_0.zip

    在给定的压缩包文件"boost_1_53_0.zip"中,我们找到了Boost库的版本1.53.0。这个版本发布于2013年,虽然不是最新的,但仍然是许多项目中广泛使用的稳定版本。 Boost库的主要目标是提高C++的性能和功能,使其更符合...

    boost_1_79_0源码安装包

    这个"boost_1_79_0源码安装包"是Boost库的第1.79.0版本,专为Windows平台设计。以下将详细介绍如何在Windows环境下编译和安装这个源码包,以及使用Boost库的一些关键知识点。 1. **下载与解压**: 首先,你需要从...

    orthanc ThirdPartyDownloads:boost_1_69_0_bcpdigest-1.5.6.tar.gz

    标题中的"orthanc ThirdPartyDownloads:boost_1_69_0_bcpdigest-1.5.6.tar.gz"指的是Orthanc项目的第三方依赖下载,其中包含的是Boost库的一个特定版本,即1.69.0,以及一个名为bcpdigest的工具,版本为1.5.6。...

    boost_1_53_0.tar.gz

    通过阅读boost_1_53_0中的源码,我们可以理解这些功能的实现原理,进一步提升我们的并发编程能力。 其次,Boost库中的智能指针(如boost::shared_ptr和boost::unique_ptr)在C++11标准中被采纳,成为std::shared_...

    boost_1_72_0 64位

    在本案例中,"boost_1_72_0 64位"指的是Boost库的特定版本1.72.0,专门为64位Windows系统编译优化。 Boost库包含了大量的组件,如: 1. **算法库**:提供了许多高级的算法,如排序、查找、数学函数等,这些通常在...

    boost_1_69_0

    "boost_1_69_0"是Boost库的一个特定版本,发布于2019年,包含了从早期版本到1.69.0期间的所有改进和新特性。 1. **多用途工具**: Boost库包含各种用途的组件,如线程管理(Boost.Thread)、智能指针(Boost....

    shared_from_this() in Constructor:直接替换std :: shared_ptr + std :: enable_shared_from_this-开源

    显然,许多人不喜欢标准std :: enable_shared_from_this类不允许在构造函数中调用shared_from_this()。 猜猜是什么:应该填补这个空白。 boost库也可以这样做,但是它不允许在析构函数中创建shared_ptrs,并且它不...

    boost_1_59_0.tar.gz.zip

    在 https://sourceforge.net/projects/boost/files/boost/1.59.0/boost_1_59_0.tar.gz/download 下载了好几个小时.. 解压为 boost_1_59_0.tar.gz 之后就可以用了

    boost_date_time-vc100-mt-1_49.dll

    标题中的"boost_date_time-vc100-mt-1_49.dll"是一个动态链接库(DLL)文件,属于Boost库的一部分,专门用于日期和时间处理。Boost库是一个广泛使用的C++库集合,旨在提升C++的标准库功能,提供跨平台的、高质量的、...

    boost_1_58_0.tar.gz

    《Boost库详解——以boost_1_58_0为例》 Boost库是C++社区开发的一个开源库,它提供了一系列高效、灵活且跨平台的编程工具,旨在提升C++的标准库功能。Boost_1_58_0是Boost库的一个特定版本,发布于2015年,包含了...

    boost_1_59_0.tar.gz.下载.txt

    用于mysql 5.7.27 源码编译,用到依赖包 boost_1_59_0.tar.gz

    boost_1_74_0.tar.gz

    boost_1_74_0.tar.gz, boost c++库

    boost_1_67_0.tar.gz,openfst-1.6.7.tar.gz

    "boost_1_67_0.tar.gz"是Boost C++库的一个版本,它是一个开源库集合,提供了许多C++标准库没有的功能,如线程管理、正则表达式、日期时间处理、文件系统操作、数学函数等。在深度学习领域,Boost库常常被用来增强...

Global site tag (gtag.js) - Google Analytics