Как использовать 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
. Но не уверен, что это действительно так?
Ответы
Ответ 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 ) ;