J'essaie d'utiliser boost::optional
comme ci-dessous.
#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;
}
Je reçois l'erreur suivante
prog.exe: /usr/local/boost-1.55.0/include/boost/optional/optional.hpp:631: boost :: optional :: type de référence boost :: optional :: get () [avec T = Ma classe; boost :: optional :: reference_type = myClass &]: Assertion `this-> is_initialized () 'a échoué.
Vraisemblablement, la variable facultative n’est pas initialisée correctement. Comment le faire correctement?
EDIT :: Vous avez de très bonnes réponses, juste quelques questions supplémentaires 1. Est-ce une bonne idée d'utiliser make_optional
à la fin de la fonction 'func'
et de la retourner? Aussi 2. Je pensais assigner boost::none
pour souligner que je n’ai aucune valeur à attribuer et c’est pourquoi boost::none
. Mais pas sûr que ce soit valable?
Un boost::optional
construit par défaut est vide - il ne contient pas de valeur, vous ne pouvez donc pas appeler get()
dessus. Vous devez l'initialiser avec une valeur valide:
boost::optional<myClass> value = myClass();
Vous pouvez également utiliser une fabrique in-place pour éviter l'initialisation de la copie (mais la copie sera probablement éliminée de toute façon); Cependant, je n'ai aucune expérience dans ce domaine et je ne peux donc pas donner d'exemple.
En remarque, vous pouvez utiliser ->
à la place de get()
, comme ceci:
value->setInt(10);
Mais ce n'est qu'une question de préférence stylistique, les deux sont également valables.
Deux approches faciles:
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;
}
notez que renvoyer une optional
à partir d'une fonction qui ne renvoie jamais une option vide est une mauvaise idée.
optional
se comporte comme un pointeur sur l'accès en lecture - vous ne pouvez lire la valeur de celle-ci que si vous avez déjà vérifié qu'il y a quelque chose à lire. Vous pouvez vérifier s'il y a quelque chose à lire en faisant bool something_to_read = opt;
.
Vous pouvez cependant lui écrire à tout moment. S'il n'y a rien là-bas, cela crée quelque chose. S'il y a quelque chose là, ça écrase.
.get()
est une lecture, pas une écriture, une opération. (il "lit" la référence) Son utilisation est sûre uniquement lorsque la optional
est activée et contient des données. De manière confuse, vous pouvez écrire dans la valeur de retour "read access" .get()
, car il s'agit d'une référence non const.
Alors peut-être que "lire" et "écrire" sont de mauvais mots à utiliser. :)
Il est parfois utile de penser à facultatif en tant que valeur et pointeur mélangés. Il existe un pointeur potentiellement nul vers un tampon de mémoire appartenant à l'utilisateur qui peut ou non contenir une copie du type.
Si le pointeur à l'intérieur de facultatif est null, la mémoire tampon n'est pas initialisée. S'il pointe vers le tampon, celui-ci est initialisé.
.get()
supprime ce pointeur et renvoie la référence résultante sans vérification. =
vérifie le pointeur. S'il est nul, il effectue une copie-construction du rhs dans le tampon et le positionne. Sinon, il ne fait qu'attribuer à la mémoire tampon.
(Le pointeur est conceptuel: généralement implémenté sous la forme d'un drapeau bool
).
Je trouve que l'utilisation de *optional
est meilleure que optional.get()
, car le "vous devez vérifier avant de déréférencer" est plus évident avec l'opérateur de déréférencement.
Comment le faire correctement?
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};
}
En remarque, ce code n'a pas besoin de boost :: optional, car il n'y a pas de branche de code qui retourne un objet vide (c'est sémantiquement équivalent au retour d'une instance myClass).
Pour retourner un optionnel vide, utilisez ceci:
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
}
Code client idiomatique (ne pré-initialisez pas vos valeurs):
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;
}
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
selon boost, ctor optionnel créera un obj optionnel invalide
optional<T> def ; //not initalize with a obj T
assert ( !def ) ;