2014-08-28 2 views
9

Ich habe eine Klasse, die wie dieseWie speichert man eine Art von "null" in C++ double oder int Variable?

struct A { 
    double a1; 
    int b1; 
    double a2; 
    int b2; 
}; 

Ich habe abzulesen eine Datei Wert für a1, b1, a2 und b2 aussieht. Die meiste Zeit sind alle vier Zahlen in der Datei, aber manchmal gibt es nur zwei Zahlen.

Wenn zwei Zahlen sind, möchte ich die Werte in a1 speichern und b1 und ich möchte in a2 und b2 „nichts“ speichern. Wenn a2 und b2 Zeiger wären, könnte ich ihnen einfach zuweisen nullptr, aber sie sind keine Zeiger.

Kann ich etwas in double und int Variablen speichern, um anzuzeigen, dass "nichts" gespeichert ist?

Ich weiß Boost.Optional ist verfügbar, aber ich versuche, diese Bibliothek zu vermeiden.

+0

Wählen Sie einen Wert, von dem Sie wissen, dass Ihre Variablen ihn niemals annehmen werden, und nennen Sie ihn 'NULL'. Dann vergleiche die Variablen mit "NULL". Die erste Wahl ist oft 0 oder -1 – scohe001

+0

Das ist das Problem, ich kenne keine Werte, die meine Variablen niemals haben werden. – jlconlin

+1

@Josh: Nein, nenne es nicht 'NULL'. Geben Sie ihm einen eindeutigen Namen, der nicht mit der Standardbibliothek in Konflikt steht. –

Antwort

8

Sie könnten NAN dem doppelten a2 zuweisen, was auch anzeigen würde, dass der int b2 ungültig ist.

This page für NAN-Nutzung.

+1

Das scheint eine vernünftige Lösung zu sein. Was ist der Unterschied zwischen 'std :: numeric_limits :: quiet_NaN()' und 'std :: nan (" 1 ")'? – jlconlin

+1

Ich denke, dass quiet_NaN() ist implementierungsspezifisch, std :: nan ("1") erzeugt eine bestimmte Menge von Bits. In Bezug auf die Informationen, die Sie zur Verfügung gestellt haben, sollte es keine Rolle spielen, da Sie is_nan() verwenden sollten, um trotzdem nach NaN zu suchen. – jonas25007

+0

Nur eine Warnung, Sie möchten "stille" NaNs verwenden, andernfalls würde es eine Gleitkommaausnahme auslösen, wenn Sie es auf NaN setzen. Wenn Sie nicht wissen, ob Sie leise NaNs haben oder nicht, sollten Sie keine NaNs verwenden. –

3

Entweder haben Sie einen Wert, der nicht legal ist oder nicht. Wenn Sie einen Wert haben, der nicht legal ist (wie -1), verwenden Sie ihn als Sentinel. Wenn nicht, dann nein. Verwenden Sie Boost.Optional oder rollen Sie Ihre eigene Klasse "value plus boolean".

+0

Wenn Sie einen unzulässigen Wert als Sentinel verwenden, sollten Sie ein Assert hinzufügen, das prüft, ob ein angegebener Wert legal ist. – Walter

1
  1. Sie können einen Wert auswählen, die nicht in den Textdateien (ein unzulässiger Wert) sein kann, wie 0, -1, std::numeric_limits<int>::max(). Wenn Sie die Daten verarbeiten, verwenden Sie den Wert nur, wenn er nicht dem ungültigen Wert (oder Sentinel) entspricht.
  2. Fügen Sie ein bool angibt, wie viele Werte gibt es:

    struct A { 
        double a1; 
        int b1; 
        double a2; 
        int b2; 
        bool has_4_nums; 
    }; 
    
  3. einen Zeiger verwenden (int* oder std::unique_ptr<int> per @ Peter Pei Guo) und nullptr zuweisen, wenn sie nicht existieren.

3

Sie können nicht. Ich kann an zwei alternative Möglichkeiten denken:

  1. Verwendung int *; oder
  2. Verwenden Sie einen Wert, der in Ihrem Kontext sicher ungültig ist. Zum Beispiel, wenn es nie negativ sein kann, dann verwenden Sie -1, um null anzuzeigen. Aber ich bevorzuge immer noch den ersten Weg, da seine Korrektheit nicht von der Anforderung oder dem Kontext abhängt.
+0

Oder 'std :: unique_ptr ' wie das ist C++ 11 – matsjoyce

+0

@matsjoyce: Einführung dynamische Zuordnung, wo Sie sonst nicht brauchen, ist es wahrscheinlich eine schlechte Idee, zumindest für die Leistung. –

+0

Wahr, aber um 'int *' zu verwenden, müssten Sie eine Liste aller verwendeten Nummern führen, um den Zeiger am Leben zu erhalten. – matsjoyce

0

Sie haben eine zwei Optionen boost::optional und damit die Abhängigkeit zu vermeiden Boost: Der std::experimental::optional Compiler

  • verwenden, die von GCC verfügbar ist 4.9+ (und Clang in der letzten Versionen IIRC) mit -std=c++14.

  • Verwenden Sie die "Referenzimplementierung" von Andrzej Krzemieński für std::experimental::optional von GitHub. Es ist nur Header, so dass Sie nur den Header zu einem Projekt kopieren können (natürlich auf die Lizenz bezahlen)

1

Sieht aus wie Sie Probleme haben, weiter die Straße hinunter gehen. Die Notwendigkeit zu wissen, wie viele Werte gültig sind, wird durch die Codebasis gestreut.

Ich schlage vor, eine Fabrik und Basisklasse zu haben. Im Wesentlichen werden Sie mindestens zwei Klassen haben:

struct two_values 
{ 
    double a1; 
    int b1; 
}; 

struct four_values : public two_values 
{ 
    double a2; 
    int b2; 
}; 

Wenn explizit eine Funktion, die vier Werte erfordert, verwenden Sie die four_values Struktur in der Erklärung. Ansonsten verwenden Sie die Struktur two_values in der Funktionsdeklaration.

Diese Beziehung besagt, dass eine four_values Instanz in jeder Funktion verwendet werden kann, die eine two_values Struktur benötigt.

Alternative
Eine Alternative ist std::vector für Ihre Artikel zu verwenden:

struct Container 
{ 
    std::vector<double> a_values; 
    std::vector<int> b_values; 
}; 

Ein Vorteil dieser Konstruktion ist, dass die Vektoren kann Ihnen sagen, wie viele Artikel gibt es und das Konzept ist erweiterbar, in falls du 6 Gegenstände brauchst.

+0

Während die ursprüngliche Frage über "Nullable" Floats und Ints war, denke ich, dass diese Antwort der beste Rat ist. Sie können wahrscheinlich die Behandlung von 2 oder 4 Werten in das Objektmodell einbauen und es sauber machen. Wenn Sie nullbare Werte zulassen, öffnen Sie jetzt bis zu 16 mögliche Kombinationen (2 ** 4), wenn Sie in Wirklichkeit nur 2 mögliche Kombinationen wünschen. Was machen Sie, wenn 'a1 'nulled ist, oder' a2' nulled ist, aber nicht 'b2'? –

0

Alternativ können Sie zusätzliche Mitglied hinzufügen zu wissen, ob normale Mitglieder betroffen sind, so etwas wie:

struct A { 
    double a1; 
    int b1; 
    double a2; 
    int b2; 
    bool is_assigned[4]; 
}; 

oder

struct A { 
    double a1; 
    int b1; 
    double a2; 
    int b2; 
    double* p_a1; // point to a1 when initialized, else nullptr 
    int* p_b1; // point to b1 when initialized, else nullptr 
    double* p_a2; // point to a2 when initialized, else nullptr 
    int* p_b1; // point to b2 when initialized, else nullptr 
}; 
0
struct A { 
    double a1; 
    int b1; 
    double a2; 
    int b2; 

}; 

hierfür können Sie einfach jede Art der Nutzung Variable, um anzugeben, ob diesen Variablen zwei oder vier Werte zugewiesen sind.

nehmen wie einen Variablennamen zugeordnet = -1

Also, wenn Ihr Eingangswert positiv sind dann, wenn zwei Werte in Datei sind dann nur

a2 = b2 = assigend

Also, wenn Sie machen checken Sie dann einfach, ob der Wert von a2 und b2 -1 oder etwas anderes ist,

Verwandte Themen