如何使用boost::可选

How to use boost::optional

本文关键字:可选 boost 何使用      更新时间:2023-10-16

我正在尝试使用boost::optional,如下所示。

#include <iostream>
#include <string>
#include <boost/optional.hpp>
struct myClass
{
int myInt;
void setInt(int input) { myInt = input; }
int  getInt(){return myInt; }
};
boost::optional<myClass> func(const std::string &str)
{
boost::optional<myClass> value;
if(str.length() > 5)
{
// If greater than 5 length string. Set value to 10
value.get().setInt(10);
}
else if (str.length() < 5)
{
// Else set it to 0
value.get().setInt(0);
}
else
{
// If it is 5 set the value to 5
value.get().setInt(5);
}
return value;
}

int main()
{
boost::optional<myClass> v1 = func("3124");
boost::optional<myClass> v2 = func("helloWorld");
boost::optional<myClass> v3 = func("hello");
if (v1)
std::cout << "v1 is valid" << std::endl;
else
std::cout << "v1 is not valid" << std::endl;
if (v2)
std::cout << "v2 is valid" << std::endl;
else
std::cout << "v3 is not valid" << std::endl;
if (v3)
std::cout << "v3 is valid" << std::endl;
else
std::cout << "v3 is not valid" << std::endl;
return 0;
}

我得到以下错误

prog.exe:/usr/local/boost-1.55.0/include/boost/optional/optional.hpp:631:boost::optional::reference_type boost:=myClass;boost::可选::reference_type=myClass&]:断言`this->is_initialized()'失败。

可能是可选变量未正确初始化。如何以正确的方式进行?

编辑:得到了一些非常好的答案,只需要再问几个问题。在'func'函数的末尾使用make_optional并返回它是个好主意吗?还有2。我想分配boost::none来强调我没有可分配的值,这就是boost::none的原因。但不确定这是否有效?

默认构造的boost::optional为空-它不包含值,因此您不能对其调用get()。您必须使用有效值对其进行初始化:

boost::optional<myClass> value = myClass();

或者,您可以使用原位工厂来避免副本初始化(但副本很可能会被删除);然而,我没有这方面的经验,所以我不能提供一个例子。


附带说明,您可以使用->来代替get(),如下所示:

value->setInt(10);

但这只是风格偏好的问题,两者都同样有效。

如何以正确的方式进行?

boost::optional<myClass> func(const std::string &str)
{
if(str.length() > 5)
return myClass{10};
if(str.length() < 5)
return myClass{0};
return myClass{5};
}

附带说明一下,此代码不需要boost::optional,因为没有返回空对象的代码分支(在语义上等同于返回myClass实例)。

要返回空的可选项,请使用以下选项:

boost::optional<myClass> func(const std::string &str)
{
if(str.length() > 5)
return myClass{10};
if(str.length() < 5)
return myClass{0};
return boost::none; // return empty object
}

典型的客户端代码(不要预先初始化您的值):

int main()
{
if (auto v1 = func("3214"))
// use *v1 to access value
std::cout << "v1 is valid" << std::endl;
else
std::cout << "v1 is not valid" << std::endl;
return 0;
}

两种简单的方法:

boost::optional<myClass> func(const std::string &str)
{
boost::optional<myClass> value;
if(str.length() > 5) // If greater than 5 length string. Set value to 10
value = 10;
else if (str.length() < 5) // Else set it to 0
value = 0;
else // If it is 5 set the value to 5
value = 5;
return value;
}
boost::optional<myClass> func(const std::string &str)
{
if(str.length() > 5) // If greater than 5 length string. Set value to 10
return 10;
else if (str.length() < 5) // Else set it to 0
return 0;
else // If it is 5 set the value to 5
return 5;
}

请注意,从从不返回空可选项的函数返回optional是个坏主意。

optional的行为类似于读取访问上的指针——如果您已经验证了有要读取的内容,则只能从中读取值。你可以通过做bool something_to_read = opt;来检查是否有什么要读的。

然而,你可以随时写信给它。如果那里什么都没有,它就会创造一些东西。如果有什么东西,它会覆盖它。

.get()是一种读取操作,而不是写入操作。(它"读取"参考)只有当optional接通并有数据时才可以安全使用。令人困惑的是,您可以写入"读取访问".get()返回值,因为它是一个非常量引用。

所以,也许"读"answers"写"是不好用的词。:)

将可选视为值和指针混合在一起有时会有所帮助。可能有一个指向内存所属缓冲区的空指针,该缓冲区可能包含也可能不包含该类型的副本。

如果可选项中的指针为null,则缓冲区未初始化。如果它指向缓冲区,则缓冲区被初始化。

.get()取消引用该指针并返回结果引用,而不进行检查。=检查指针,如果指针为null,它将从rhs复制构造到缓冲区并设置指针。如果不是,它只分配给缓冲区。

(指针是概念性的:通常实现为bool标志)。

我发现使用*optionaloptional.get()更好,因为"在取消引用之前必须检查"在取消引用运算符中更明显。

boost::optional<myClass> func(const std::string &str)
{
boost::optional<myClass> value; //not init is invalid
if(str.length() > 5)       // If greater than 5 length string. Set value to 10
value = 10;
else if (str.length() < 5) // Else set it to 0
value = 0;
return value;
}

v1 is valid
v2 is valid
v3 is not valid

根据boost的说法,可选的默认ctor将创建一个可选的obj作为无效的

optional<T> def ; //not initalize with a obj T
assert ( !def ) ;