38

我正在尝试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::optional::get() [with T = myClass; boost::optional::reference_type = myClass&]: 断言 `this->is_initialized()' 失败。

据推测,可选变量未正确初始化。如何以正确的方式做到这一点?

编辑:: 得到了一些非常好的答案,还有几个问题 1.在函数make_optional末尾使用'func'并返回它是一个好主意吗?另外 2. 我正在考虑分配boost::none以强调我没有分配价值,这就是为什么boost::none。但不确定这是否有效?

4

4 回答 4

32

默认构造boost::optional是空的——它不包含值,所以你不能调用get()它。您必须使用有效值对其进行初始化:

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

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


作为旁注,您可以使用->代替get(),如下所示:

value->setInt(10);

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

于 2014-03-06T14:52:10.293 回答
11

如何以正确的方式做到这一点?

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;
}
于 2014-03-06T15:03:19.280 回答
9

两种简单的方法:

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()返回值,因为它是一个非常量引用。

所以也许“读”和“写”是不好用的词。:)

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

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

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

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

我发现 using*optional比 更好optional.get(),因为“在取消引用之前必须检查”对于取消引用运算符更为明显。

于 2014-03-06T14:57:33.297 回答
1
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 ) ;
于 2015-12-11T16:25:18.293 回答