参考链接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");
}
结果:

1691

被折叠的 条评论
为什么被折叠?



