c++ - Cómo usar boost:: opcional
boost-optional (4)
¿Cómo hacerlo de la manera correcta?
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};
}
Como nota al margen, este código no necesita refuerzo :: opcional, porque no hay una rama de código que devuelva un objeto vacío (es semánticamente equivalente a devolver una instancia de myClass).
Para devolver un opcional vacío, use esto:
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
}
Código de cliente idiomático (no inicialice previamente sus valores):
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;
}
Estoy tratando de usar boost::optional
como se muestra a continuación.
#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;
}
Me sale el siguiente 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 &]: la aserción `this-> is_initialized () ''falló.
Presumiblemente, la variable opcional no se inicializa correctamente. ¿Cómo hacerlo de la manera correcta?
EDITAR: Tengo algunas respuestas muy buenas, solo un par de preguntas más 1. ¿Es una buena idea usar make_optional
al final de ''func''
y devolverla? También 2. Estaba pensando en asignar boost::none
para enfatizar que no tengo ningún valor que asignar y por eso boost::none
. ¿Pero no estoy seguro si eso es válido?
Dos enfoques fáciles:
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;
}
tenga en cuenta que devolver una optional
de una función que nunca devuelve una opción vacía es una mala idea.
optional
comporta como un puntero en el acceso de lectura: solo puede leer su valor si ya ha verificado que hay algo para leer. Puede verificar si hay algo para leer haciendo bool something_to_read = opt;
.
Usted puede, sin embargo, escribir en él cada vez que. Si no hay nada allí, crea algo. Si hay algo allí, lo sobrescribe.
.get()
es una operación de lectura, no de escritura. ("lee" la referencia) Solo es seguro usarlo cuando el optional
está activado y tiene datos. Confusamente, puede escribir en el valor de retorno de "acceso de lectura" .get()
, ya que es una referencia no constante.
Así que tal vez "leer" y "escribir" son malas palabras para usar. :)
A veces es útil pensar en lo opcional como un valor y un puntero mezclados. Es posible que haya un puntero nulo a un búfer de memoria propio que puede o no contener una copia del tipo.
Si el puntero dentro del opcional es nulo, entonces el búfer no está inicializado. Si apunta al búfer, entonces el búfer se inicializa.
.get()
elimina referencias que .get()
y devuelven la referencia resultante sin verificar. =
comprueba el puntero, si es nulo, realiza una construcción de copia de los rhs en el búfer y establece el puntero. Si no, simplemente asigna al búfer.
(El puntero es conceptual: generalmente implementado como un indicador bool
).
Considero que usar *optional
es mejor que optional.get()
, ya que el "debe comprobar antes de eliminar la referencia" es más obvio con el operador de referencia.
Un boost::optional
construido de forma predeterminada boost::optional
está vacío: no contiene un valor, por lo que no puede llamar a get()
. Tienes que inicializarlo con un valor válido:
boost::optional<myClass> value = myClass();
Alternativamente, puede utilizar una fábrica en el lugar para evitar la inicialización de la copia (pero la copia probablemente será eliminada de todos modos); sin embargo, no tengo experiencia con eso, así que no puedo dar un ejemplo.
Como nota al margen, puede usar ->
en lugar de get()
, así:
value->setInt(10);
Pero eso es solo una cuestión de preferencia estilística, ambos son igualmente válidos.
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
según boost, el ctor predeterminado opcional creará un objeto opcional como inválido
optional<T> def ; //not initalize with a obj T
assert ( !def ) ;