optional

参考链接1:https://blog.youkuaiyun.com/jiemashizhen/article/details/125732276
原文链接2:https://blog.youkuaiyun.com/ColdWindHA/article/details/108768640
    C++17 在 STL 中引入了std::optional,就像std::variant一样,std::optional是一个“和类型(sum type)”,也就是说,std::optional类型的变量要么是一个T类型的__变量__,要么是一个表示“什么都没有”的__状态__。这个状态也有自己的类型和值:类型是std::nullopt_t,值为std::nullopt。看起来是不是很熟悉?没错,概念上它和nullptr十分相似,区别就是后者是一个关键字罢了。

    std::optional几乎拥有所有我们想要的性质:任何一个T类型或可以隐式转换成T类型的变量都可以用来构造它的对象,同样我们也可以用std::nullopt或默认构造函数来构造它,这个时候我们得到的变量意义是“nothing”罢了。我们使用has_value()函数来询问std::optional此时是否有值,如果有的话,我们使用value()函数来获取他的值。如果std::optional没有值时我们仍然调用value(),我们将获得一个std::bad_optional_access异常报错奖励。需要注意的是,std::optional在内部存储T变量,并没有用到动态分配内存,其实说实在的,在C++标准中,动态内存这种行为时时刻刻都是不被建议的。

有的时候实现一个函数,需要通过返回值表示状态,然后通过参数传递一个指针或引用获得函数的功能返回。

比如设计一个函数,获得一个数组里的最大值:

#include <iostream>
using namespace std;
 
int getMax(const int *data, int len, int& max)
{
	if(data == nullptr || len == 0)        //如果是个无效的数组
	{
		return 0;                          //返回0,代表函数执行失败
	}
	else
	{
		max = data[0];
		for(int i = 1; i < len; ++i)
		{
			if(data[i] > max)
			{
				max = data[i];
			}
		}
		return 1;                         //返回1,代表函数执行成功
	}
}
 
int main()
{
	int data[] = {4, 3, 6, 7, 2};
	int max = 0;
	if(getMax(data, sizeof(data)/sizeof(int), max))    //首先通过函数返回值确定状态
	{
		cout<<"max is "<<max<<endl;        //函数执行成功,输出最大值
	}
	else
	{
		cout<<"invalid data"<<endl;        //函数执行失败,给予提示
	}
	return 0;
}

像getMax这种函数,还是很常见的,通常的解决方案就是如上例所示,但这种方式需要额外的传递一个参数。

另一种方法就是返回魔数,比如返回int所能表示的最小值,或者根据程序逻辑来说,某个不可能出现的值,但这种魔数具有很大的不确定性,因为说不定哪天原先认为不可能的,就变成了可能。

C++17提供了一种新的方案,可以较好的解决这个问题,那就是optional。

#include <iostream>
#include <optional>
using namespace std;
 
optional<int> getMax(const int *data, int len)
{
	if(data == nullptr || len == 0)
	{
		return nullopt;    //返回nullopt,代表无效的状态
	}
	else
	{
		int max = data[0];
		for(int i = 1; i < len; ++i)
		{
			if(data[i] > max)
			{
				max = data[i];
			}
		}
		return max;        //返回最大值
	}
}
 
int main()
{
	int data[] = {4, 3, 6, 7, 2};
	optional<int>&& max = getMax(data, sizeof(data)/sizeof(int));
	if(max)                             //检查状态
	{
		cout<<"max is "<<*max<<endl;    //读取到最大值
	}
	else
	{
		cout<<"invalid data"<<endl;
	}
	return 0;
}

可见,optional实际上有点类似variant,可以表示一个无效的状态(nullopt),也可以表示一个有意义的值。

除了上例的方式,也可以通过has_value成员函数来检查此时对象是不是表示一个有意义的值,并通过value函数获得这个有意义的值,因此上例也可以通过这种方式实现main函数:

int main()
{
	int data[] = {4, 3, 6, 7, 2};
	optional<int>&& max = getMax(data, sizeof(data)/sizeof(int));
	if(max.has_value())
	{
		cout<<"max is "<<max.value()<<endl;
	}
	else
	{
		cout<<"invalid data"<<endl;
	}
	return 0;
}

值得一提的是,optional内部并没有通过在堆上分配内存来实现。

继续看例子:

std::optional<string> GetName()
{
	std::optional<string> opt;
	bool bfag = true;
	if (bfag)
	{
		return  "hello world";
	}
	else
	{
		return  nullopt;
	}

}


std::optional<std::vector<int> > GetVc()
{
	vector<int> opt;
	bool bfag = true;
	if (bfag)
	{
		opt.push_back(1);
		opt.push_back(2);
		opt.push_back(3);

		return opt;
	}
	else
	{
		return  nullopt;
	}	
}

void main()
{
	auto s = GetName();
	if (s)
	{
		cout << *s << endl;
		cout << s.value() << endl;
	}

	auto&& opt = GetVc();
	if (opt)
	{
		for (auto node : *opt)
		{
			cout << node << endl;
		}
	}
	system("pause");
}

结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发如雪-ty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值