(C++17) optional的使用

文章目录

  • 前言与需求
  • 使用
    • 简单示例
    • 构造
      • 空值
      • std::in_place 原位构造
      • 推导指引
      • std::make_optional
    • 访问
      • 取值
      • 逻辑判断
  • END

前言与需求

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);
}

构造

空值

#include 
#include 
#include 

int main() {
    std::optional<std::string> op0;
    std::optional<std::string> op1 = {};
    std::optional<std::string> op2 = std::nullopt;
}

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;
}

推导指引

都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;
}

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;
}

访问

取值

直接使用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;
}

逻辑判断

因为有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;
    }
}



END

你可能感兴趣的:(C/C++,c++,开发语言)