• C++17使用std::optional表示一个可能存在的值


    前言

    平时写代码会遇到一种传递参数特殊值标记特殊流程,或者函数返回值存在魔法数的情况,很需要一种标记参数或返回值状态的结构,那么在 C++17 标准下提供了 std::optional 这个模板类,可以表示一个值不存在的状态,一起来看看用法吧。

    返回一个bool值

    以下例子纯属虚构,只为说明问题,无实际意义

    bool getBoolVal(int a, int b)
    {
        int* n = new int;
        if (!n)
            return false;
    
        *n = 1;
    
        if (a + *n > b)
            return true;
        else
            return false;
    }
    
    int main()
    {
        if (getBoolVal(10, 9))
            std::cout << 1 << std::endl;
        else
            std::cout << 1 << std::endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这个例子中的函数 getBoolVal 本意是想返回一个 bool 类型的判断结果,但是函数中有一些异常情况时,比如申请内存异常时,也会返回一个bool值,这是与原判断结果语义不同的,所以需要单独返回这种情况,如果也放到同一个返回值中会导致含义模糊,这时可以考虑使用引用变量参数来返回实际比较结果。

    bool getBoolVal(int a, int b, bool& ret)
    {
        int* n = new int;
        if (!n)
            return false;
    
        *n = 1;
    
        if (a + *n > b)
            ret = true;
        else
            ret = false;
    
        return true;
    }
    
    int main()
    {
        bool ret = false;
        if (getBoolVal(10, 9, ret))
            std::cout << "error" << std::endl;
        else
        {
            if (ret)
                std::cout << 1 << std::endl;
            else
                std::cout << 0 << std::endl;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    这个引用参数 ret 使用起来有点不方便,那把两个值都返回怎么样,虽然C++不允许有多个返回值,但可以把它们包装成 std::pair 或者 std::tuple 来返回,再来改写一下:

    std::pair<bool, bool> getBoolVal3(int a, int b)
    {
        int* n = new int;
        if (!n)
            return {false, false};
    
        *n = 1;
    
        if (a + *n > b)
            return {true, true};
        else
            return {true, false};
    }
    
    int main()
    {
        auto [err, ret] = getBoolVal(10, 9);
        if (err)
            std::cout << "error" << std::endl;
        else
        {
            if (ret)
                std::cout << 1 << std::endl;
            else
                std::cout << 0 << std::endl;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    这种方法把实际的返回值,搭配一个表示状态的 bool 变量,组成 std::pair 进行返回,基本上得到而来语义明确的目的,但是看起来还是不太优雅,而 std::optional 可以帮助我们实现类似的需求,并且代码看起来能更简洁一点。

    使用 std::optional 改写

    std::optional 本身是一个模板类:会有一个 std::nullopt

    template <class T>
    class optional;
    
    • 1
    • 2

    它内部有两种状态,要么有一个T类型的值,要么用 std::nullopt 表示没有值,查看一个 std::optional 对象是否有值,可以用 has_value() 进行判断,当一个 std::optional 有值时,可以通过用指针的方式(*号和->号)来使用它,或者用 value()函数取它的值,下面我们用它来改写一下之前的实现:

    std::optional<bool> getBoolVal4(int a, int b)
    {
        int* n = new int;
        if (!n)
            return std::nullopt;
    
        *n = 1;
    
        if (a + *n > b)
            return true;
        else
            return false;
    }
    
    
    int main()
    {
        std::optional<bool> ret = getBoolVal(10, 9);
        if (ret.has_value())
            std::cout << "error" << std::endl;
        else
        {
            if (ret.value())
                std::cout << 1 << std::endl;
            else
                std::cout << 0 << std::endl;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    使用了 std::optional 之后就把 bool 类型之前的两态变成了三态,很多类似的逻辑也被封装成了函数,使用它之后代码更清晰了,从此可以告别一些烦人的魔法数了,一些函数参数也可以使用 std::optional 来包装,用法类似,在此就不展开说了。

    总结

    • std::optional 是一个模板类,可以表示一个可能存在的值
    • std::optional 的内部有两种状态,要么表示一个T类型的值,要么用 std::nullopt 表示没有值
    • 可以用 has_value() 判断一个 std::optional 是否有值,然后用 value() 函数取它表示的值

    ==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

    子未经历过,安知此文是鸡汤,子非我,安知我不知此文是鸡汤。意见向左的人往往在内心互道傻X,而现实生活中哪有什么绝对的对错,只是出发点和眼界不同罢了,即使是真理也有适用的环境,“两点之间线段最短”,这一定是对的吗?

  • 相关阅读:
    串口转TCP/IP方案选型
    js里面有引用传递吗?
    vmlogin指纹浏览器中设置本地API进行常规自动化操作
    Openssl数据安全传输平台004:Socket C-API封装为C++类 / 服务端及客户端代码框架和实现
    [Spring]Thymeleaf——XML/XHTML/HTML5模板引擎
    WPF控件7
    如何使用前端表格控件实现数据更新?
    源码分析RocketMQ之Broker-内存映射刷盘流程
    腾讯云CVM服务器操作系统镜像大全
    Unity笔记:C#基础(1)
  • 原文地址:https://blog.csdn.net/shihengzhen101/article/details/125839078