• Std::optional 源码分析


    Std::optional 源码分析

    背景:

    std::optional 是c++17 新增的一个模版,用法也很简单,主要用于返回值是否设置了值,本文将从stl c++17的源码分析具体内部实现原理

    用法:

    C++
    #include
    #include
    #include
    #include
     
    // optional can be used as the return type of a factory that may fail
    std::optional create(bool b) {
        if (b)
            return "Godzilla";
        return {};
    }
     
    // std::nullopt can be used to create any (empty) std::optional
    auto create2(bool b) {
        return b ? std::optional{"Godzilla"} : std::nullopt;
    }
     
    // std::reference_wrapper may be used to return a reference
    auto create_ref(bool b) {
        static std::string value = "Godzilla";
        return b ? std::optional>{value}
                 : std::nullopt;
    }
     
    int main()
    {
        std::cout << "create(false) returned "
                  << create(false).value_or("empty") << '\n';
     
        // optional-returning factory functions are usable as conditions of while and if
        if (auto str = create2(true)) {
            std::cout << "create2(true) returned " << *str << '\n';
        }
     
        if (auto str = create_ref(true)) {
            // using get() to access the reference_wrapper's value
            std::cout << "create_ref(true) returned " << str->get() << '\n';
            str->get() = "Mothra";
            std::cout << "modifying it changed it to " << str->get() << '\n';
        }
    }

    Output

    C++
    create(false) returned empty
    create2(true) returned Godzilla
    create_ref(true) returned Godzilla
    modifying it changed it to Mothra

    https://en.cppreference.com/w/cpp/utility/optional

    源码分析

    本文将从最简单的std::optional 进行,其内部实现还是挺复杂的

    首先看下std::optional定义

    std::optional

    C++
    template
    class optional
        : private __optional_move_assign_base<_Tp>
        , private __optional_sfinae_ctor_base_t<_Tp>
        , private __optional_sfinae_assign_base_t<_Tp>
    {
        using __base = __optional_move_assign_base<_Tp>;
    public:
        using value_type = _Tp;
    }

    因为我们推到类型是int所以下边的__optional_sfinae_ctor_base_t 与 __optional_sfinae_assign_base_t 可以不用去关注,内部经过sfinae过后是空的实现

    接下来看下__optional_move_assign_base的实现

    __optional_move_assign_base

    C++
    template     is_trivially_destructible<_Tp>::value &&
        is_trivially_move_constructible<_Tp>::value &&
        is_trivially_move_assignable<_Tp>::value>
    struct __optional_move_assign_base : __optional_copy_assign_base<_Tp>
    {
        using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;
    };

    template
    struct __optional_move_assign_base<_Tp, false> : __optional_copy_assign_base<_Tp>
    {
        using value_type = _Tp;
        using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base;

        _LIBCPP_INLINE_VISIBILITY
        __optional_move_assign_base() = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_move_assign_base(const __optional_move_assign_base& __opt) = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_move_assign_base(__optional_move_assign_base&&) = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_move_assign_base& operator=(const __optional_move_assign_base&) = default;

        _LIBCPP_INLINE_VISIBILITY
        __optional_move_assign_base& operator=(__optional_move_assign_base&& __opt)
            noexcept(is_nothrow_move_assignable_v &&
                     is_nothrow_move_constructible_v)
        {
            this->__assign_from(_VSTD::move(__opt));
            return *this;
        }
    };

    通过上边可以看到__optional_move_assign_base 有2个版本的实现一个是对于class有destructible,以及移动构造等,由于我们是推导的是int,所以第一个经过sfinae,推导不通过,会选择下边这个特化版本__optional_move_assign_base<_Tp, false>,这个strcut 继承__optional_copy_assign_base,所以我看下它的实现

    __optional_copy_assign_base

    C++
    template     is_trivially_destructible<_Tp>::value &&
        is_trivially_copy_constructible<_Tp>::value &&
        is_trivially_copy_assignable<_Tp>::value>
    struct __optional_copy_assign_base : __optional_move_base<_Tp>
    {
        using __optional_move_base<_Tp>::__optional_move_base;
    };

    template
    struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp>
    {
        using __optional_move_base<_Tp>::__optional_move_base;

        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_assign_base() = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_assign_base(const __optional_copy_assign_base&) = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_assign_base(__optional_copy_assign_base&&) = default;

        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_assign_base& operator=(const __optional_copy_assign_base& __opt)
        {
            this->__assign_from(__opt);
            return *this;
        }

        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_assign_base& operator=(__optional_copy_assign_base&&) = default;
    };

    与上边类似__optional_copy_assign_base也有2个版本,这里就不详细解释了,我们推导类型是int所以选择下边的__optional_copy_assign_base<_Tp, false>特化版本,它又继承了__optional_move_base,这时候需要知道它的实现了

    __optional_move_base

    C++
    template ::value>
    struct __optional_move_base : __optional_copy_base<_Tp>
    {
        using __optional_copy_base<_Tp>::__optional_copy_base;
    };

    template
    struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp>
    {
        using value_type = _Tp;
        using __optional_copy_base<_Tp>::__optional_copy_base;

        _LIBCPP_INLINE_VISIBILITY
        __optional_move_base() = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_move_base(const __optional_move_base&) = default;

        _LIBCPP_INLINE_VISIBILITY
        __optional_move_base(__optional_move_base&& __opt)
            noexcept(is_nothrow_move_constructible_v)
        {
            this->__construct_from(_VSTD::move(__opt));
        }

        _LIBCPP_INLINE_VISIBILITY
        __optional_move_base& operator=(const __optional_move_base&) = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_move_base& operator=(__optional_move_base&&) = default;
    };

    与上边类似它也有2个版本,选择了特化版本struct __optional_move_base<_Tp, false> 

    struct __optional_move_base<_Tp, false>  又继承了__optional_copy_base<_Tp>,这里就去看下它的实现__optional_copy_base<_Tp>

    __optional_copy_base<_Tp>

    C++
    template ::value>
    struct __optional_copy_base : __optional_storage_base<_Tp>
    {
        using __optional_storage_base<_Tp>::__optional_storage_base;
    };

    template
    struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp>
    {
        using __optional_storage_base<_Tp>::__optional_storage_base;

        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_base() = default;

        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_base(const __optional_copy_base& __opt)
        {
            this->__construct_from(__opt);
        }

        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_base(__optional_copy_base&&) = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_base& operator=(const __optional_copy_base&) = default;
        _LIBCPP_INLINE_VISIBILITY
        __optional_copy_base& operator=(__optional_copy_base&&) = default;
    };

    同样它也有2个版本,最终推导选择__optional_copy_base<_Tp, false>,这个我们看下__optional_storage_base<_Tp>的定义

    __optional_storage_base<_Tp>

    C++
    template ::value>
    struct __optional_storage_base : __optional_destruct_base<_Tp>
    {
        using __base = __optional_destruct_base<_Tp>;
        using value_type = _Tp;
        using __base::__base;
        ..............
    };

    // optional is currently required ill-formed, however it may to be in the
    // future. For this reason it has already been implemented to ensure we can
    // make the change in an ABI compatible manner.
    template
    struct __optional_storage_base<_Tp, true>
    {
        using value_type = _Tp;
        using __raw_type = remove_reference_t<_Tp>;
        __raw_type* __value_;
        .........
    };

    我们推导类型是int,is_reference<_Tp>::value 不是引用,所以它推导是上个struct __optional_storage_base : __optional_destruct_base<_Tp>,所以接下来看下 __optional_destruct_base<_Tp>的实现

     __optional_destruct_base<_Tp>

    C++
    template
    struct __optional_destruct_base<_Tp, false>
    {
        typedef _Tp value_type;
        static_assert(is_object_v,
            "instantiation of optional with a non-object type is undefined behavior");
        union
        {
            char __null_state_;
            value_type __val_;
        };
        bool __engaged_;
    }

    总结 sizeof(std::optional) = ?

    通过上边源码分析,std::optional 最终数据是

    C++
        union
        {
            char __null_state_;
            value_type __val_;
        };
        bool __engaged_;

    也就是说value_type = int,所以sizeof(std::optional) == 8

    std::optional 如果没设置去get会发生什么

    很多人应该知道会抛异常,那我们就从源码来看

  • 相关阅读:
    实时数据平台设计
    Bootstrap5 网格系统
    golang validator 包的使用指北
    Java利用poi实现word,excel,ppt,pdf等各类型文档密码检测
    基于 arm64 Linux nanosleep 系统调用流程分析
    算法 - 组合总和3
    音视频标签
    【科普向】什么是CPU、什么是GPU?本机Win11的CPU和GPU配置如何
    【面试经典150 | 数组】买卖股票的最佳时机
    VS实用调式技巧
  • 原文地址:https://blog.csdn.net/c553110519/article/details/126682033