Ich versuche, boost::optional
wie folgt zu verwenden.
#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;
}
Ich bekomme folgende Fehlermeldung
prog.exe: /usr/local/boost-1.55.0/include/boost/optional/optional.hpp:631: boost :: optional :: reference_type boost :: optional :: get () [mit T = meine Klasse; boost :: optional :: reference_type = myClass &]: Assertion "this-> is_initialized ()" ist fehlgeschlagen.
Vermutlich wird die optionale Variable nicht richtig initialisiert. Wie mache ich es richtig?
BEARBEITEN: Einige sehr gute Antworten, nur ein paar weitere Fragen 1. Ist es eine gute Idee, make_optional
am Ende der 'func'
-Funktion zu verwenden und zurückzugeben? Auch 2. Ich dachte daran, boost::none
zuzuweisen, um zu betonen, dass ich keinen Wert zuweisen kann, und deshalb boost::none
. Aber nicht sicher, ob das gültig ist?
Ein standardmäßig erstellter boost::optional
ist leer - er enthält keinen Wert, sodass Sie get()
nicht aufrufen können. Sie müssen es mit einem gültigen Wert initialisieren:
boost::optional<myClass> value = myClass();
Alternativ können Sie eine In-Place-Factory verwenden, um die Initialisierung der Kopie zu vermeiden (die Kopie wird jedoch höchstwahrscheinlich trotzdem entfernt). Ich habe jedoch keine Erfahrung damit, daher kann ich kein Beispiel geben.
Als Randnotiz können Sie ->
anstelle von get()
wie folgt verwenden:
value->setInt(10);
Aber das ist nur eine Frage der Stilvorlieben, beide sind gleichermaßen gültig.
Zwei einfache Ansätze:
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;
}
beachten Sie, dass die Rückgabe eines optional
von einer Funktion, die niemals ein leeres optionales Element zurückgibt, eine schlechte Idee ist.
optional
verhält sich wie ein Zeiger beim Lesezugriff - Sie können nur lesen den Wert daraus, wenn Sie bereits überprüft haben, dass dort etwas zu lesen ist. Sie können überprüfen, ob etwas zu lesen ist, indem Sie bool something_to_read = opt;
ausführen.
Sie können jedoch jederzeit schreiben. Wenn dort nichts ist, entsteht etwas. Wenn dort etwas ist, wird es überschrieben.
.get()
ist eine Lese- und keine Schreiboperation. (liest die Referenz) Es ist nur sicher zu verwenden, wenn optional
eingeschaltet ist und Daten enthält. Verwirrenderweise können Sie auf den .get()
-Rückgabewert "Lesezugriff" schreiben, da es sich um eine nicht konstante Referenz handelt.
Vielleicht sind "Lesen" und "Schreiben" schlechte Wörter. :)
Es ist manchmal hilfreich, sich optional als Wert und Zeiger zu bezeichnen. Es gibt möglicherweise einen Nullzeiger auf einen eigenen Puffer des Speichers, der eine Kopie des Typs enthalten kann oder nicht.
Wenn der Zeiger im optionalen Element null ist, ist der Puffer nicht initialisiert. Wenn es auf den Puffer zeigt, wird der Puffer initialisiert.
.get()
dereferenziert diesen Zeiger und gibt die resultierende Referenz zurück, ohne zu prüfen. =
prüft den Zeiger. Wenn er null ist, erstellt er eine Kopie von rhs in den Puffer und setzt den Zeiger. Wenn nicht, wird es einfach dem Puffer zugewiesen.
(Der Zeiger ist konzeptuell: in der Regel als bool
-Flag implementiert).
Ich finde, dass *optional
besser ist als optional.get()
, da das "Sie müssen prüfen müssen, bevor Sie dereferenzieren" mit dem Dereferenzierungsoperator deutlicher ist.
Wie mache ich es richtig?
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};
}
Als Randbemerkung benötigt dieser Code boost :: optional nicht, da es keinen Codezweig gibt, der ein leeres Objekt zurückgibt (dies entspricht semantisch der Rückgabe einer myClass-Instanz).
Verwenden Sie Folgendes, um ein leeres optionales Element zurückzugeben:
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
}
Idiomatic-Clientcode (Werte nicht vorinitialisieren):
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
gemäß Boost wird ein optionaler Standard-Ctor ein optionales Objekt als ungültig erstellen
optional<T> def ; //not initalize with a obj T
assert ( !def ) ;