webentwicklung-frage-antwort-db.com.de

Prüfen, ob eine Variable initialisiert ist

Anscheinend wäre dies ein Duplikat, aber vielleicht ist es so offensichtlich, dass es nicht gefragt wurde ...

Ist dies der richtige Weg, um zu überprüfen, ob eine Variable (kein Zeiger) in einer C++ - Klasse initialisiert wird?

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        // do something with mCharacter.
    }

    if ( ! mDecimal )
    {
        // define mDecimal.
    }
}
45
user542687

Es gibt keine Möglichkeit, zu überprüfen, ob der Inhalt einer Variablen undefiniert ist oder nicht. Am besten können Sie einen Signal-/Sentinel-Wert (zum Beispiel im Konstruktor) zuweisen, um anzuzeigen, dass eine weitere Initialisierung erforderlich ist.

28

Eine nicht definierte Variable führt zu einem Kompilierungsfehler.

Sie fragen, ob sie initialisiert ist. Die Initialisierung ist jedoch nur ein Wert, den Sie im Konstruktor auswählen und zuweisen sollten.

Zum Beispiel:

class MyClass
{
    MyClass() : mCharacter('0'), mDecimal(-1.0){};
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter != '0')
    {
        // touched after the constructor
        // do something with mCharacter.
    }

    if ( mDecimal != -1.0 )
    {
        // touched after the constructor
        // define mDecimal.
    }
}

Sie sollten mit einem Standardwert initialisieren, der natürlich etwas im Kontext Ihrer Logik bedeutet.

20
littleadv

Abhängig von Ihren Anwendungen (und vor allem, wenn Sie bereits boost verwenden) möchten Sie möglicherweise nach boost::optional suchen.

(UPDATE: Ab C++ 17 ist optional jetzt Bestandteil der Standardbibliothek, als std::optional )

Es hat die Eigenschaft, nach der Sie suchen, und verfolgt, ob der Steckplatz tatsächlich einen Wert enthält oder nicht. Standardmäßig ist er so aufgebaut, dass er keinen Wert enthält und als falsch ausgewertet wird. Wenn er jedoch als wahr ausgewertet wird, können Sie ihn dereferenzieren und den umschlossenen Wert abrufen.

class MyClass
{
    void SomeMethod();

    optional<char> mCharacter;
    optional<double> mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        // do something with *mCharacter.
        // (note you must use the dereference operator)
    }

    if ( ! mDecimal )
    {
        // call mDecimal.reset(expression)
        // (this is how you assign an optional)
    }
}

Weitere Beispiele finden Sie in der Boost-Dokumentation .

14
HostileFork

Mit C++ 17 können Sie mit std::optional prüfen, ob eine Variable initialisiert ist:

#include <optional>
#include <iostream>  // needed only for std::cout

int main() {
    std::optional<int> variable;

    if (!variable) {
        std::cout << "variable is NOT initialized\n";
    }

    variable = 3;

    if (variable) {
        std::cout << "variable IS initialized and is set to " << *variable << '\n';
    }

    return 0;
}

Dies erzeugt die Ausgabe:

variable is NOT initialized
variable IS initialized and is set to 3

Um std::optional in dem Code zu verwenden, den Sie bereitgestellt haben, müssen Sie den Bibliotheksheader <optional> Standard hinzufügen und den jeweiligen Variablendeklarationen std::optional<...> hinzufügen:

#include <optional>

class MyClass
{
    void SomeMethod();

    std::optional<char> mCharacter;
    std::optional<double> mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        std::cout << *mCharacter;  // do something with mCharacter.
    }

    if ( ! mDecimal )
    {
        mDecimal = 3.14159;  // define mDecimal.
    }
}
8
Elmar

Standardmäßig können Sie nicht wissen, ob eine Variable (oder ein Zeiger) initialisiert wurde oder nicht. Da jedoch jeder andere Ihnen die "einfache" oder "normale" Herangehensweise sagt, gebe ich Ihnen etwas anderes zum Nachdenken. Hier ist, wie Sie könnten so etwas nachverfolgen (nein, ich persönlich würde das niemals tun, aber vielleicht haben Sie andere Bedürfnisse als ich).

class MyVeryCoolInteger
{
public:
    MyVeryCoolInteger() : m_initialized(false) {}

    MyVeryCoolInteger& operator=(const int integer)
    {
        m_initialized = true;
        m_int = integer;
        return *this;
    }

    int value()
    {
        return m_int;
    }

    bool isInitialized()
    {
        return m_initialized;
    }

private:
    int m_int;
    bool m_initialized;
};
3
Chris Eberle

Mit C++ - 11 können Sie die Variable mithilfe von intelligenten Zeigern speichern. Betrachten Sie diese MVE, wobei das Verhalten von toString() davon abhängt, ob bar initialisiert wird oder nicht:

#include <memory>
#include <sstream>

class Foo {

private:
    std::shared_ptr<int> bar;

public:
    Foo() {}
    void setBar(int bar) {
        this->bar = std::make_shared<int>(bar);
    }
    std::string toString() const {
        std::ostringstream ss;
        if (bar)           // bar was set
            ss << *bar;
        else               // bar was never set
            ss << "unset";
        return ss.str();
    }
};

Verwenden Sie diesen Code

Foo f;
std::cout << f.toString() << std::endl;
f.setBar(42);
std::cout << f.toString() << std::endl;

erzeugt die Ausgabe

unset
42
2
Twonky

Es gibt keinen vernünftigen Weg, um zu überprüfen, ob ein Wert initialisiert wurde.

Wenn es Ihnen wichtig ist, ob etwas initialisiert wurde, anstatt zu prüfen, ob etwas vorhanden ist, fügen Sie Code in die Konstruktoren ein, um sicherzustellen, dass sie immer initialisiert werden und fertig sind.

1
Jerry Coffin

Da MyClass ein POD-Klassentyp ist, haben diese nicht statischen Datenelemente unbestimmte Anfangswerte, wenn Sie eine nicht statische Instanz von MyClass erstellen. Nein, dies ist keine gültige Methode, um zu überprüfen, ob sie auf ein bestimmtes Nicht-Objekt initialisiert wurden -Nullwert ... Sie gehen im Grunde davon aus, dass sie mit Null initialisiert werden. Dies ist jedoch nicht der Fall, da Sie sie nicht in einem Konstruktor wertinitialisiert haben.

Wenn Sie die nicht statischen Datenelemente Ihrer Klasse mit Null initialisieren möchten, sollten Sie am besten eine Initialisierungsliste und einen Klassenkonstruktor erstellen. Zum Beispiel:

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;

    public:
        MyClass();
};

MyClass::MyClass(): mCharacter(0), mDecimal(0) {}

Die Initialisierungsliste im Konstruktor über Wert initialisiert Ihre Datenelemente auf Null. Sie können nun richtig davon ausgehen, dass jeder Wert ungleich Null für mCharacter und mDecimal von Ihnen an einer anderen Stelle in Ihrem Code festgelegt wurde und Werte enthält, die nicht Null sind, auf die Sie ordnungsgemäß reagieren können.

1
Jason

Wenn Sie meinen, wie Sie prüfen können, ob Member-Variablen initialisiert wurden, können Sie dies tun, indem Sie ihnen im Konstruktor Sentinel-Werte zuweisen. Wählen Sie Sentinel-Werte als Werte, die bei normaler Verwendung dieser Variablen niemals auftreten werden. Wenn ein ganzer Variablenbereich als gültig betrachtet wird, können Sie einen Booleschen Wert erstellen, um anzuzeigen, ob er initialisiert wurde.

#include <limits>

class MyClass
{
    void SomeMethod();

    char mCharacter;
    bool isCharacterInitialized;
    double mDecimal;

    MyClass()
    : isCharacterInitialized(false)
    , mDecimal( std::numeric_limits<double>::quiet_NaN() )
    {}


};


void MyClass::SomeMethod()
{
    if ( isCharacterInitialized == false )
    {
        // do something with mCharacter.
    }

    if ( mDecimal != mDecimal ) // if true, mDecimal == NaN
    {
        // define mDecimal.
    }
}
1
Praetorian

Sie können die Variable in einer Assertion referenzieren und dann mit -fsanitize=address erstellen:

void foo (int32_t& i) {
    // Assertion will trigger address sanitizer if not initialized:
    assert(static_cast<int64_t>(i) != INT64_MAX);
}

Dies führt dazu, dass das Programm mit einer Stack-Ablaufverfolgung zuverlässig abstürzt (im Gegensatz zu undefiniertem Verhalten).

0
sffc

In der C++ - Sprache gibt es keine Möglichkeit zu überprüfen, ob eine Variable initialisiert wurde oder nicht (obwohl Klassentypen mit Konstruktoren automatisch initialisiert werden).

Stattdessen müssen Sie Konstruktoren bereitstellen, die Ihre Klasse mit einem gültigen Status initialisieren. Statische Code-Prüfer (und möglicherweise einige Compiler) können Ihnen dabei helfen, fehlende Variablen in Konstruktoren zu finden. Auf diese Weise müssen Sie sich keine Sorgen darüber machen, dass Sie sich in einem falschen Zustand befinden, und die if -Überprüfungen in Ihrer Methode können vollständig verschwinden.

0
Mark B

Wenn Sie beispielsweise Zeichenfolgen anstelle von Zeichen verwenden, können Sie Folgendes tun:

    //a is a string of length 1
    string a;
    //b is the char in which we'll put the char stored in a
    char b;
    bool isInitialized(){
      if(a.length() != NULL){
        b = a[0];
        return true;
      }else return false;
    }
0
Allan Lago