GCC STL 源码学习(三)—— optional

本文深入探讨了GCC STL中的optional类,包括结构体定义、共用体、成员函数、拷贝与赋值操作、相关函数的实现细节。文章通过源码分析,解释了optional如何管理和存储数据,以及在不同情况下的行为。
摘要由CSDN通过智能技术生成

optional

1 _Optional_payload_base结构体

这个模板管理std::optional的实际数据。

定义

template <typename _Tp> struct _Optional_payload_base {
   
  using _Stored_type = remove_const_t<_Tp>;
};

有一个存储类型的定义,就是_Tp去掉const修饰符后的类型。

_Storage共用体

struct _Empty_byte {
   };

template <typename _Up, bool = is_trivially_destructible_v<_Up>>
union _Storage {
   
  constexpr _Storage() noexcept : _M_empty() {
   }

  template <typename... _Args>
  constexpr _Storage(in_place_t, _Args &&...__args)
      : _M_value(std::forward<_Args>(__args)...) {
   }

  template <typename _Vp, typename... _Args>
  constexpr _Storage(std::initializer_list<_Vp> __il, _Args &&...__args)
      : _M_value(__il, std::forward<_Args>(__args)...) {
   }

  _Empty_byte _M_empty;
  _Up _M_value;
};

template <typename _Up> union _Storage<_Up, false> {
   
  constexpr _Storage() noexcept : _M_empty() {
   }

  template <typename... _Args>
  constexpr _Storage(in_place_t, _Args &&...__args)
      : _M_value(std::forward<_Args>(__args)...) {
   }

  template <typename _Vp, typename... _Args>
  constexpr _Storage(std::initializer_list<_Vp> __il, _Args &&...__args)
      : _M_value(__il, std::forward<_Args>(__args)...) {
   }

  // User-provided destructor is needed when _Up has non-trivial dtor.
  ~_Storage() {
   }

  _Empty_byte _M_empty;
  _Up _M_value;
};

_Storage<_Stored_type> _M_payload;

_Storage模板的第一个模板参数为_Up,代表了实际存储的对象的类型。第二个参数为is_trivially_destructible_v<_Up>。当其为false的时候,有一个特化的版本,里面定义了一个析构函数。一般地,这个共用体的默认构造函数初始化了一个_Empty_byte对象,是一个空的结构体对象。另外存在两个构造函数,会根据传入的参数初始化一个_up类型的变量。

_Storage类型的变量_M_payload构成了_Optional_payload_base的核心成员变量,是此结构体的数据实际存储的地方,也是std::optional的实际存储数据的地方。

另一数据成员:_M_engaged

bool _M_engaged = false;

这个变量表明了这个结构体是否真实承载了数据,也可以理解为_M_payload为空还是有真实数据的标志。

构造、析构、拷贝、赋值等函数

_Optional_payload_base() = default;
~_Optional_payload_base() = default;

template <typename... _Args>
constexpr _Optional_payload_base(in_place_t __tag, _Args &&...__args)
    : _M_payload(__tag, std::forward<_Args>(__args)...), _M_engaged(true) {
   }

template <typename _Up, typename... _Args>
constexpr _Optional_payload_base(std::initializer_list<_Up> __il,
                                 _Args &&...__args)
    : _M_payload(__il, std::forward<_Args>(__args)...), _M_engaged(true) {
   }

// Constructor used by _Optional_base copy constructor when the
// contained value is not trivially copy constructible.
constexpr _Optional_payload_base(bool __engaged,
                                 const _Optional_payload_base &__other) {
   
  if (__other._M_engaged)
    this->_M_construct(__other._M_get());
}

// Constructor used by _Optional_base move constructor when the
// contained value is not trivially move constructible.
constexpr _Optional_payload_base(bool __engaged,
                                 _Optional_payload_base &&__other) {
   
  if (__other._M_engaged)
    this->_M_construct(std::move(__other._M_get()));
}

// Copy constructor is only used to when the contained value is
// trivially copy constructible.
_Optional_payload_base(const _Optional_payload_base &) = default;

// Move constructor is only used to when the contained value is
// trivially copy constructible.
_Optional_payload_base(_Optional_payload_base &&) = default;

_Optional_payload_base &operator=(const _Optional_payload_base &) = default;

_Optional_payload_base &operator=(_Optional_payload_base &&) = default;

注意参数中有__engaged参数的拷贝、移动构造函数和不带这个参数的拷贝、移动构造函数的区别。

  • 带有这个参数的拷贝、移动构造函数,当other的engaged参数为true时,调用_M_construct函数。当包含的具体数据类型不是trivially copy constructible的,_Optional_base会使用这种函数。
  • 不带这个参数的,为默认实现。当包含的具体数据类型是trivially copy constructible的,_Optional_base会使用这种函数。

其他成员函数

// used to perform non-trivial copy assignment.
constexpr void _M_copy_assign(const _Optional_payload_base &__other) {
   
  if (this->_M_engaged && __other._M_engaged)
    this->_M_get() = __other._M_get();
  else {
   
    if (__other._M_engaged)
      this->_M_construct(__other._M_get());
    else
      this->_M_reset();
  }
}

// used to perform non-trivial move assignment.
constexpr void _M_move_assign(_Optional_payload_base &&__other) noexcept(
    __and_v<is_nothrow_move_constructible<_Tp>,
            is_nothrow_move_assignable<_Tp>>) {
   
  if (this->_M_engaged && __other._M_engaged)
    this->_M_get() = std::move(__other._M_get());
  else {
   
    if (__other._M_engaged)
      this->_M_construct(std::move(__other._M_get()));
    else
      this->_M_reset();
  }
}
template <typename... _Args>
void _M_construct(_Args &&...__args) noexcept(
    is_nothrow_constructible_v<_Stored_type, _Args...>) {
   
  ::new ((void *)std::__addressof(this->_M_payload))
      _Stored_type(std::forward<_Args>(__args)...);
  this->_M_engaged = true;
}

constexpr void _M_destroy() noexcept {
   
  _M_engaged = false;
  _M_payload._M_value.~_Stored_type();
}

// The _M_get() operations have _M_engaged as a precondition.
// They exist to access the contained value with the appropriate
// const-qualification, because _M_payload has had the const removed.

constexpr _Tp &_M_get() noexcept {
    return this->_M_payload._M_value; }

constexpr const _Tp &_M_get() const noexcept {
   
  return this->_M_payload._M_value;
}

// _M_reset is a 'safe' operation with no precondition.
constexpr void _M_reset() noexcept {
   
  if (this->_M_engaged)
    _M_destroy();
}

2 _Optional_payload结构体

基本定义

// Class template that manages the payload for optionals.
template <typename _Tp,
          bool /*_HasTrivialDestructor*/ = is_trivially_destructible_v<_Tp>,
          bool /*_HasTrivialCopy */ = is_trivially_copy_assignable_v<_Tp>
              &&is_trivially_copy_constructible_v<_Tp>,
          bool /*_HasTrivialMove */ = is_trivially_move_assignable_v<_Tp>
              &&is_trivially_move_constructible_v<_Tp>>
struct _Optional_payload;

它的模板参数第一个是_Tp,是实际的数据类型,除此之外,还有三个模板参数:

  1. 析构是trivial的吗?
  2. 拷贝构造、赋值是trivial的吗?
  3. 移动构造、赋值是trivial的吗?

根据这三个的取值不同,有下面几种不同的特化形式:

// Payload for potentially-constexpr optionals (trivial copy/move/destroy).
template <typename _Tp>
struct _Optional_payload<_Tp, true, true, true>
    : _Optional_payload_base<_Tp> {
   
  using _Optional_payload_base<_Tp>::_Optional_payload_base;

  _Optional_payload() = default;
};

// Payload for optionals with non-trivial copy construction/assignment.
template <typename _Tp>
struct _Optional_payload<_Tp, true, false, true>
    : _Optional_payload_base<_Tp> {
   
  using _Optional_payload_base<_Tp>::_Optional_payload_base;

  _Optional_payload() = default;
  ~_Optional_payload() = default;
  _Optional_payload(const _Optional_payload &) = default;
  _Optional_payload(_Optional_payload &&) = default;
  _Optional_payload &operator=(_Optional_payload &&) = default;

  // Non-trivial copy assignment.
  constexpr _Optional_payload &operator=(const _Optional_payload &__other) {
   
    this->_M_copy_assign(__other);
    return *this;
  }
};

// Payload for optionals with non-trivial move construction/assignment.
template <typename _Tp>
struct _Optional_payload<_Tp, true, true, false>
    : _Optional_payload_base<_Tp> {
   
  using _Optional_payload_base<_Tp>::_Optional_payload_base;

  _Optional_payload() = default;
  ~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值