Notas de lectura del código fuente STL (6) - Cualquiera

prefacio

He oído hablar de él antes, pero no lo he usado mucho. Se usa para reemplazar void por conversión de tipo, que es más seguro que void conversion.

Versión STL

La versión stl utilizada en este artículo es libc++ 13.0, que pertenece al proyecto LLVM.

Proyecto LLVM Github

Si encuentra definiciones de macro desconocidas, puede consultar el documento Macros de visibilidad de símbolos

Cualquier

any es un tipo admitido solo en c++ 17. Cualquier tipo se puede almacenar en su interior. El principio es usar el borrado de tipos. Hay dos tipos comunes de borrado de tipos en c++. Uno es a través de funciones virtuales, como function Use virtual functions para el borrado de tipos, y hay otro método que usa tipos vacíos, cualquiera usa este método.

Echemos un vistazo a la definición y los miembros internos de cualquier

class _LIBCPP_TEMPLATE_VIS any
{
    typedef __any_imp::_Action _Action;
    using _HandleFuncPtr =  void* (*)(_Action, any const *, any *, const type_info *,
      const void* __fallback_info);

    union _Storage {
        constexpr _Storage() : __ptr(nullptr) {}
        void *  __ptr;
        __any_imp::_Buffer __buf;
    };
    template <class>
    friend struct __any_imp::_SmallHandler;
    template <class>
    friend struct __any_imp::_LargeHandler;

    _HandleFuncPtr __h = nullptr;
    _Storage __s;
}

Se puede encontrar que any no es una clase de plantilla. Hay un puntero de función y un lugar de almacenamiento en el interior. Cuando el objeto interno es más pequeño que 3 sizeof (void ), se almacenará en sí mismo, y si es más grande, lo hará. solicitar espacio en el montón. La operación de any básicamente no se realiza por sí misma sino a través de _SmallHandler y _LargeHandler en __any_imp.

Constructor

Dado que hay varios constructores y cada plantilla es muy larga, elijamos una típica.

//声明
template <class _ValueType, class ..._Args,
    class _Tp = decay_t<_ValueType>,
    class = enable_if_t<
        is_constructible<_Tp, _Args...>::value &&
        is_copy_constructible<_Tp>::value
    >
  >
  _LIBCPP_INLINE_VISIBILITY
  explicit any(in_place_type_t<_ValueType>, _Args&&... __args);

//定义
template <class _ValueType, class ..._Args, class _Tp, class>
any::any(in_place_type_t<_ValueType>, _Args&&... __args) {
  __any_imp::_Handler<_Tp>::__create(*this, _VSTD::forward<_Args>(__args)...);
}

template <class _Tp>
  using _Handler = conditional_t<
    _IsSmallObject<_Tp>::value, _SmallHandler<_Tp>, _LargeHandler<_Tp>>;

Se puede encontrar que la plantilla se usa para detectar si el tipo almacenado tiene un constructor correspondiente y un constructor de copia, y la definición se confía a _Handler para su procesamiento, y _Handler es en realidad uno en tiempo de compilación. : Operación ternaria, si es un objeto pequeño, el _Handler es _SmallHandler, de lo contrario es _LargeHandler.

Este es básicamente el caso de los constructores de copia y de movimiento. Veamos qué hacen _SmallHandler y _LargeHandler más adelante.

__cualquier_imp

_Manejador pequeño

Dentro de _SmallHandler hay algunas funciones estáticas, como crear, copiar, mover, etc.

Veamos primero la función crear.

template <class ..._Args>
    _LIBCPP_INLINE_VISIBILITY
    static _Tp& __create(any & __dest, _Args&&... __args) {
        typedef allocator<_Tp> _Alloc;
        typedef allocator_traits<_Alloc> _ATraits;
        _Alloc __a;
        _Tp * __ret = static_cast<_Tp*>(static_cast<void*>(&__dest.__s.__buf));
        _ATraits::construct(__a, __ret, _VSTD::forward<_Args>(__args)...);
        __dest.__h = &_SmallHandler::__handle;
        return *__ret;
    }

Se puede encontrar que la construcción de any se lleva a cabo aquí, usando el asignador para asignar espacio en los __s de any y construyéndolo, y luego copiando el puntero de función _SmallHandler::__handle a la __h de any.

En _SmallHandler, también hay una función estática __handle que se registrará en cualquier __h.La función principal de esta función es llamar a diferentes funciones de acuerdo con los parámetros.

static void* __handle(_Action __act, any const * __this, any * __other,
                           type_info const * __info, const void* __fallback_info)
     {
        switch (__act)
        {
        case _Action::_Destroy:
          __destroy(const_cast<any &>(*__this));
          return nullptr;
        case _Action::_Copy:
            __copy(*__this, *__other);
            return nullptr;
        case _Action::_Move:
          __move(const_cast<any &>(*__this), *__other);
          return nullptr;
        case _Action::_Get:
            return __get(const_cast<any &>(*__this), __info, __fallback_info);
        case _Action::_TypeInfo:
          return __type_info();
        }
    }

_Manejador grande

La estructura de _LargeHandler es básicamente la misma que la de _SmallHandler, excepto que la ubicación del espacio asignado es diferente, por lo que no lo describiré en detalle.

función any_cast

El último es convertir any al tipo original de la función any_cast.any_cast se usa esencialmente para static_cast, pero realizará una verificación nula en el objeto en any, y se lanzará una excepción si está vacío.

template <class _ValueType>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
_ValueType any_cast(any const & __v)
{
    using _RawValueType = __uncvref_t<_ValueType>;
    static_assert(is_constructible<_ValueType, _RawValueType const &>::value,
                  "ValueType is required to be a const lvalue reference "
                  "or a CopyConstructible type");
    auto __tmp = _VSTD::any_cast<add_const_t<_RawValueType>>(&__v);
    if (__tmp == nullptr)
        __throw_bad_any_cast();
    return static_cast<_ValueType>(*__tmp);
}

Supongo que te gusta

Origin blog.csdn.net/ninesnow_c/article/details/126499063
Recomendado
Clasificación