c++17中的optional

一、std::optional

在英文中,optional表示“可选的,随意的”。那在c++中用这个模板表示什么意思呢?“类模板 std::optional 管理一个可选的容纳值,既可以存在也可以不存在的值。”也就是说,这个类模板表示这个值是可能存在的。它有什么用呢?这个就说来话长了。在早期的C/C++中,如何表示空这个问题,搞c++的人都明白,这是一个比较难缠的事儿。早期指针就是用NULL值(0)来判断。但其实这个并不是特别友好,而且还需要提前处理指针。但是如果是和别人协作,别人忘记处理了,又是一个事儿。在后面提供了nullptr算是解决了很大的一部分问题。但是,指针的问题解决了,不代表类似的问题都解决了。
在C/C++中,非指针如何表示一个空值。举一个例子,一函数用来创建一个类对象,如果它没有成功返回什么?像这种情况的解决办法,一般是搞这个bool值用来看是否执行成功,再来拿取对象;或者搞个魔数1,2,3等等来判断,原理都是一样。更或者,可以采用异常处理的方式,这个在c++里就有些惨不忍睹了。前者代码丑陋,后者是犯不着这么大费周章。
那有没有一个类似于nullptr的东西呢?有,std::nullopt_t ,它“是空类类型,用于指示 optional 类型拥有未初始化状态。特别是 std::optional 有一个以 nullopt_t 为单参数的构造函数,它创建不含值的 optional 。”这不就引出来今天的主题std::optional。看一下它的定义:

struct nullopt_t {
    explicit constexpr nullopt_t(int) {}
};
template< class T >
class optional;

std::optional在确定有值的情况并不会分配内存而只是使用存在值的内存。注意,它模拟了一个对象而不是一个指针,尽管其定义了尽管定义了 operator*() 和 operator->() 运算符。此类提供了一个类似智能指针创建的接口std::make_optional,有兴趣可以查查官网来看一下。

二、应用场景

要说std::optional的应用场景还真是多。原来凡是这种取得对象变量的地方都可以用它来替换,它基本解决了对变量处理空值的问题,这对于一些诸如工厂类和属性(对象)值获取的地方都可以直接应用。尤其是对于一些库的对外接口,不需要再处理空值异常的状态信息,可以在库外调用者直接处理,代码会更简单明了,处理异常更清晰便捷。
说句直白的话,这些个类或者接口的作用,目的就是使c++的编程简化,虽然学得东西略多,但用起来却更容易,也就好吸引更多的开发者加入到自己的阵营里来,这就是目的。

三、例程

看一个例程:

#include <string>
#include <functional>
#include <iostream>
#include <optional>
 
// optional 可用作可能失败的工厂的返回类型
std::optional<std::string> create(bool b) 
{
    if(b)
        return "Godzilla";
    else
        return {};
}
 
// 能用 std::nullopt 创建任何(空的) std::optional
auto create2(bool b) 
{
    return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}
 
// std::reference_wrapper 可用于返回引用
auto create_ref(bool b) 
{
    static std::string value = "Godzilla";
    return b ? std::optional<std::reference_wrapper<std::string>>{value}
             : std::nullopt;
}
 
int main()
{
    std::cout << "create(false) returned "<< create(false).value_or("empty") << '\n';
 
    // 返回 optional 的工厂函数可用作 while 和 if 的条件
    if (auto str = create2(true)) 
   {
        std::cout << "create2(true) returned " << *str << '\n';
    }
 
    if (auto str = create_ref(true))
   {
        // 用 get() 访问 reference_wrapper 的值
        std::cout << "create_ref(true) returned " << str->get() << '\n';
        str->get() = "Mothra";
        std::cout << "modifying it changed it to " << str->get() << '\n';
    }
}

运行结果:

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

很重要,但不是必须。这就是std::optional。

四、总结

std::optional是一个和类型(sum type, 表达的是值的个数是所有type的总和), 区别于struct所表达的积类型.还记得std::variant 不,这两个std::optional表示可能有,std::variant 表示要么有(要么是这个,要么是那个)。
其实有的时候儿真心不原意讲这些固有的库的内容。但是为什么还是要讲呢?一个重要原因是,许多应用在这些上面使用会有一些非常好的效果。同样,在模板编程中,它们能起到一些辅助作用,关键的时刻,这些辅助作用还挺重要。本着学以致用的态度,来看待这个问题,会更好的体会本文的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值