• (C++17) optional的使用


    前言与需求

    optional 》adj.可选择的,选修的

    在编程与实际项目中,可能会出现数据不合法的需求与状态。

    在以往通常的使用中,通常会为每种数据类型定义一个值作为不合法的标志。比如int = -1, string = “str_invalid”等等。

    这种方式有许多弊端:

    1. 编写时麻烦
    2. 这些不合法数据在有的场景下可能是有效的
    3. 团队协作时需要来回确认
    4. 等等

    为了处理这种可能出现不合法的情况,C++17推出了std::opational<>来处理这个问题。

    在C++20和C++23对此还进行了加强,但本文不对这些加强做过多演示。

    使用

    std::optional - cppreference.com

    简单示例

    该实例简洁明了,能够基本了解optional的使用大意。

    注意在optional是空值时,如还需要取值则会出现异常

    terminate called after throwing an instance of ‘std::bad_optional_access’
    what(): bad optional access

    #include 
    #include 
    #include 
    
    std::optional<std::string> create_optional(bool flag) {
        if (flag) {
            return "pass option";
        } else {
            // {} 也可行
            // return {};
            return std::nullopt;
        }
    }
    
    void test(bool flag) {
        auto opt = create_optional(flag);
    
        // 可以直接作为if判断
        if (opt) {
            // 两种取值方法
            std::cout << opt.value() << std::endl;
            std::cout << *opt << std::endl;
    
            // 可以修改
            opt.value() = "modify opt.value()";
            std::cout << opt.value_or("no data") << std::endl;
        } else {
            // terminate called after throwing an instance of
            // 'std::bad_optional_access'
            //  what():  bad optional access
            // std::cout << opt.value() << std::endl;
            std::cout << opt.value_or("no data") << std::endl;
        }
    }
    
    int main() {
        test(true);
        test(false);
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    构造

    空值

    #include 
    #include 
    #include 
    
    int main() {
        std::optional<std::string> op0;
        std::optional<std::string> op1 = {};
        std::optional<std::string> op2 = std::nullopt;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    std::in_place 原位构造

    原位构造。使用std::in_place可以直接使用构造函数了。

    #include 
    #include 
    #include 
    
    int main() {
        // 调用 std::string( initializer_list ) 构造函数
        std::optional<std::string> opt1(std::in_place, {'a', 'b', 'c'});
    
        // 调用 std::string( size_type count, CharT ch ) 构造函数
        std::optional<std::string> opt2(std::in_place, 3, 'A');
    
        std::cout << opt1.value() << '\n' << opt2.value() << std::endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    推导指引

    都C++17了,推到指引必不可少

    注意数组还是退化成 T*

    #include 
    #include 
    
    int main() {
        int arr[2];
        // std::optional opt
        std::optional opt{arr};
    
        // class std::optional
        std::optional str = "abc";
    
        using namespace std::literals;
        // class std::optional
        std::optional str_i = "abc"s;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    std::make_optional

    用对应的make函数进行构造。

    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main() {
        auto opt = std::make_optional<std::vector<int>>(5, 2);
        for (int i : *opt) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    
        std::string str{"hello world"};
        auto        opts = std::make_optional<std::string>(std::move(str));
        std::cout << std::quoted(opts.value_or("empty value"))
                  << std::endl;
        std::cout << str << std::endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    访问

    取值

    直接使用operator*()或者value()即可

    注意,考虑空值时需要套用上带默认值版本的value_or()

    #include 
    #include 
    #include 
    
    int main() {
        auto opt = std::make_optional<std::string>("Hello World");
    
        std::cout << opt.value() << std::endl;
        std::cout << *opt << std::endl;
        std::cout << opt.value_or("no data") << std::endl;
    
        // 都可以修改
        // opt.value() = "modify data";
        *opt = "modify data";
        if (opt.has_value()) {
            std::cout << opt.value_or("no data") << std::endl;
        }
    
        // 重置
        opt.reset();
        std::cout << opt.value_or("no data") << std::endl;
    
        // 异常
        // terminate called after throwing an instance of 'std::bad_optional_access'
        // what():  bad optional access
        // std::cout << opt.value() << std::endl;
    }
    
    • 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

    逻辑判断

    因为有operator bool()所以可以直接在if等逻辑判断中使用。

    #include 
    #include 
    #include 
    
    int main() {
        auto opt = std::make_optional<std::string>("Hello World");
    
        if (opt.has_value()) {
            std::cout << opt.value_or("no data") << std::endl;
        }
        if (opt) {
            std::cout << opt.value_or("no data") << std::endl;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14



    END

  • 相关阅读:
    qml ProgressBar用法介绍
    分布式多协议接入网关FluxMQ-2.0功能说明
    Python线程
    javascript 基础知识点整理
    【计算机网络实验】NAT配置实验
    c# 国内外ORM 框架 dapper efcore sqlsugar freesql hisql sqlserver数据常规插入测试性能对比
    jupyter notebook 中文本编辑快捷键
    STM32H750之FreeRTOS学习--------(六)FreeRTOS的列表和列表项
    /apache/lib/libapr-1.so.0: undefined symbol: dlopen
    读论文:Real-Time Encrypted Traffic Classification via Lightweight Neural Networks
  • 原文地址:https://blog.csdn.net/CUBE_lotus/article/details/134301097