GCC STL 源码解析(二)—— any

本文深入探讨了GCC STL中`any`类的实现细节,包括内部存储方式、数据成员、构造函数、拷贝和移动操作以及相关函数。重点介绍了如何根据类型特性决定对象存储在内部缓冲区还是堆上,以及如何通过manager函数进行对象的创建、拷贝和销毁。
摘要由CSDN通过智能技术生成

1 主要变量与函数

存储

// Holds either pointer to a heap object or the contained object itself.
union _Storage {
   
  constexpr _Storage() : _M_ptr{
   nullptr} {
   }

  // Prevent trivial copies of this type, buffer might hold a non-POD.
  _Storage(const _Storage &) = delete;
  _Storage &operator=(const _Storage &) = delete;

  void *_M_ptr;
  aligned_storage<sizeof(_M_ptr), alignof(void *)>::type _M_buffer;
};

这个共用体_Storage是any类的存储实体,它可以使用_M_buffer作为实际的存储,或者使用_M_ptr指向在heap上存储的实际对象。

那么如何判定是存储在哪儿的呢?

template <typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>,
          bool _Fits = (sizeof(_Tp) <= sizeof(_Storage)) &&
                       (alignof(_Tp) <= alignof(_Storage))>
using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;

所以,如果一个类型是不抛异常的可移动构造,且能放入进_Storage的,则是internal的。

对于是否internal,对应有不同的manager:

template <typename _Tp>
using _Manager =
    conditional_t<_Internal<_Tp>::value, _Manager_internal<_Tp>,
                  _Manager_external<_Tp>>;

主要数据成员

private:
  enum _Op {
   
    _Op_access,
    _Op_get_type_info,
    _Op_clone,
    _Op_destroy,
    _Op_xfer
  };

  union _Arg {
   
    void *_M_obj;
    const std::type_info *_M_typeinfo;
    any *_M_any;
  };

  void (*_M_manager)(_Op, const any *, _Arg *);
  _Storage _M_storage;

_M_manager就是负责管理具体数据的函数指针,具体见下。

从具体代码可以看出,共用体_Arg的两个主要成员变量:_M_obj指向实际的数据位置,如_M_buffer_M_ptr_M_any指向一个any对象。

_Op_Arg一般都是在_M_manager内使用的。

内部、外部存储manager

// Manage in-place contained object.
template <typename _Tp> struct _Manager_internal {
   
  static void _S_manage(_Op __which, const any *__any, _Arg *__arg)  {
   
    // The contained object is in _M_storage._M_buffer
    auto __ptr = reinterpret_cast<const _Tp *>(&__any->_M_storage._M_buffer);
    switch (__which) {
   
    case _Op_access:
      __arg->_M_obj = const_cast<_Tp *>(__ptr);
      break;
    case _Op_get_type_info:
#if __cpp_rtti
      __arg->_M_typeinfo = &typeid(_Tp);
#endif
      break;
    case _Op_clone:
      ::new (&__arg->_M_any->_M_storage._M_buffer) _Tp(*__ptr);
      __arg->_M_any->_M_manager = __any->_M_manager;
      break;
    case _Op_destroy:
      __ptr->~_Tp();
      break;
    case _Op_xfer:
      ::new (&__arg->_M_any->_M_storage._M_buffer)
          _Tp(std::move(*const_cast<_Tp *>(__ptr)));
      __ptr->~_Tp();
      __arg->_M_any->_M_manager = __any->_M_manager;
      const_cast<any *>(__any)->_M_manager = nullptr;
      break;
    }
  }

  template <typename _Up>
  static void _S_create(_Storage &__storage, _Up &&__value) {
   
    void *__addr = &__storage._M_buffer;
    ::new (__addr) _Tp(std::forward<_Up>(__value));
  }

  template <typename... _Args>
  static void _S_create(_Storage &__storage, _Args &&...__args) {
   
    void *__addr = &__storage._M_buffer;
    ::new (__addr) _Tp(std::forward<_Args>(__args)...);
  }
};

// Manage external contained object.
te
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值