Подтвердить что ты не робот

Как использовать boost:: optional

Я пытаюсь использовать 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() [с T = мои занятия; boost:: optional:: reference_type = myClass &]: Утверждение `this- > is_initialized() 'не удалось.

Предположительно, необязательная переменная не инициализируется должным образом. Как это сделать правильно?

EDIT:: Получили очень хорошие ответы, всего пару вопросов 1. Является ли хорошей идеей использовать make_optional в конце функции 'func' и вернуть его? Также 2. Я думал о назначении boost::none, чтобы подчеркнуть, что у меня нет никакой ценности для назначения и почему boost::none. Но не уверен, что это действительно так?

4b9b3361

Ответ 1

Построенный по умолчанию boost::optional пуст - он не содержит значения, поэтому вы не можете называть его get(). Вы должны инициализировать его с допустимым значением:

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

В качестве альтернативы вы можете использовать на месте factory, чтобы избежать инициализации копирования (но копия, скорее всего, будет отменена); однако у меня нет опыта в этом, поэтому я не могу привести пример.


В качестве примечания вы можете использовать -> вместо get(), например:

value->setInt(10);

Но это только вопрос стилистического предпочтения, оба одинаково действительны.

Ответ 2

Два простых подхода:

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 и имеет данные. Смутно, вы можете записать в возвращаемое значение "read access" .get(), так как это неконстантная ссылка.

Так что, возможно, "читать" и "писать" - это плохие слова для использования.:)

Иногда полезно подумать о необязательном как смешанном значении и указателе. Существует нулевой указатель на собственный буфер памяти, который может содержать или не содержать копию типа.

Если указатель внутри необязательного значения является нулевым, то буфер не инициализируется. Если он указывает на буфер, инициализируется буфер.

.get() разметки, которые указывают и возвращают результирующую ссылку без проверки. = проверяет указатель, если он равен нулю, он создает копию-копию из rhs в буфер и устанавливает указатель. Если нет, он просто присваивает буферу.

(Указатель концептуальный: обычно реализуется как флаг bool).

Я считаю, что использование *optional лучше, чем optional.get(), поскольку "вы должны проверить перед разыменованием" более очевидно с оператором разыменования.

Ответ 3

Как это сделать правильно?

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

Ответ 4

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