C++ 如何使用 boost::optional

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22227839/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:00:28  来源:igfitidea点击:

How to use boost::optional

c++boostboost-optional

提问by polapts

I am trying to use boost::optionalas below.

我正在尝试使用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;
 }

I get following error

我收到以下错误

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&]: Assertion `this->is_initialized()' failed.

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()'失败。

Presumably, the optional variable is not initialized properly. How to do it the correct way?

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

EDIT:: Got some very good answers, just couple of more questions 1. Is it a good idea to use make_optionalat the end of 'func'function and return it? Also 2. I was thinking of assigning boost::noneto emphasize that I have no value to assign and that's why boost::none. But not sure if that is valid?

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

采纳答案by Angew is no longer proud of SO

A default-constructed boost::optionalis empty - it does not contain a value, so you can't call get()on it. You have to initialise it with a valid value:

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

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

Alternatively, you can use an in-place factoryto avoid copy initialisation (but the copy will most likely be elided anyway); however, I have no experience with that, so I can't provide an example.

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



As a side note, you can use ->in place of get(), like this:

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

value->setInt(10);

But that's just a matter of stylistic preference, both are equally valid.

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

回答by Yakk - Adam Nevraumont

Two easy approaches:

两种简单的方法:

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;
}

note that returning an optionalfrom a function that never returns an empty optional is a bad idea.

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

optionalbehaves like a pointer on read access -- you can only readthe value from it if you have already verified there is something there to read. You can check if there is something to read by doing bool something_to_read = opt;.

optional像读访问指针的行为-你只能从它的价值,如果你已经证实有那么点阅读。您可以通过执行 来检查是否有要阅读的内容bool something_to_read = opt;

You can, however, write to it whenever. If there is nothing there, it creates something. If there is something there, it overwrites it.

但是,您可以随时写入。如果那里什么都没有,它就会创造一些东西。如果那里有东西,它会覆盖它。

.get()is a reading, not a writing, operation. (it "reads" the reference) It is only safe to use when the optionalis engaged and has data. Confusingly, you can write to the "read access" .get()return value, as it is a non-const reference.

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

So maybe "read" and "write" are bad words to use. :)

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

It is sometimes helpful to think of optional as a value-and-pointer mixed together. There is a possibly null pointer to an owned buffer of memory that may, or may not hold a copy of the type.

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

If the pointer inside the optional is null, then the buffer is uninitialized. If it points at the buffer, then the buffer is initialized.

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

.get()dereferences that pointer and returns the resulting reference withoutchecking. =checks the pointer, if it is null, it does a copy-construct from the rhs into the buffer and sets the pointer. If not, it just assigns to the buffer.

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

(The pointer is conceptual: usually implemented as a boolflag).

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

I find using *optionalto be better than optional.get(), as the "you must check before you dereference" is more obvious with the dereference operator.

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

回答by utnapistim

How to do it the correct way?

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

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};
}

As a side note, this code doesn't need boost::optional, because there is no code branch that returns an empty object (it is semantically equivalent to returning a myClass instance).

作为旁注,此代码不需要 boost::optional,因为没有返回空对象的代码分支(它在语义上等同于返回 myClass 实例)。

To return an empty optional, use this:

要返回一个空的可选,使用这个:

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
}

Idiomatic client code (don't pre-initialize your values):

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

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;
}

回答by camino

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

according to boost,optional default ctor will create an optional obj as invalid

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

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