Как использовать boost :: по желанию

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

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

РЕДАКТИРОВАТЬ :: Получил несколько очень хороших ответов, только пару вопросов 1. Это хорошая идея для использования make_optional в конце 'func' функция и вернуть его? Также 2. Я думал о назначении boost::none подчеркнуть, что я не имею никакого значения, чтобы назначить, и именно поэтому boost::none, Но не уверен, что это действительно?

21

Решение

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

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

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


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

value->setInt(10);

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

21

Другие решения

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

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() возвращаемое значение, так как это неконстантная ссылка.

Так что, возможно, «читать» и «писать» — плохие слова для использования. 🙂

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

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

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

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

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

8

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

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 :: option, потому что нет ветки кода, которая возвращает пустой объект (это семантически эквивалентно возвращению экземпляра 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;
}
6

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