Forum: PC-Programmierung [C++] Vermeidung von redudanten Daten


von Peter (Gast)


Lesenswert?

Hallo zusammen,

zuerst möchte ich mich für den recht unspezifischen Thread-Titel 
entschuldigen; leider lässt sich das Thema nicht so knapp 
zusammenfassen.
Bei einem aktuellen Projekt kommt folgender Code (stark vereinfacht und 
gekürzt) zum Einsatz:
1
#include <string>
2
#include <vector>
3
4
class Attribute
5
{
6
  public:
7
    Attribute(const std::string& name) : 
8
      name(name)
9
    {
10
    }
11
    
12
    const std::string name;
13
};
14
15
class FP_Attribute : public Attribute
16
{
17
  public:
18
    FP_Attribute(const std::string& name, float value, float min_value, float max_value) :
19
      Attribute(name),
20
      default_value(value),
21
      min_value(min_value),
22
      max_value(max_value)
23
    {
24
      set_value(value);
25
    }
26
    
27
    void set_value(float value) { /* checks constraints and sets value */ }
28
    inline float get_value() const noexcept { return value; }
29
  
30
    const float default_value;
31
    const float min_value;
32
    const float max_value;
33
    
34
  private:
35
    float value;
36
};
37
38
class Attribute_Set
39
{
40
  public:
41
    typedef std::vector<Attribute*> attributes_t;
42
43
    void register_attribute(Attribute& attribute)
44
    {
45
      attributes.push_back(&attribute);
46
    }
47
    
48
    template<typename... Args>
49
    void register_attributes(Args&&... args)
50
    {
51
      using expander = int[];
52
      (void) expander{ 0, (register_attribute(args), void(), 0)... };
53
    }
54
55
    inline const attributes_t& get_attributes() const { return attributes; }
56
  
57
  private:
58
    attributes_t attributes;
59
};

Dieser dient dazu, auf einfache Art und Weise viele verschiedene Klassen 
mit unterschiedlichen Attributen anzulegen, wie z.B. im nachfolgenden 
Beispiel:
1
class Car : public Attribute_Set
2
{
3
  public:
4
    Car()
5
    {
6
      register_attributes(length, width, height, max_speed, mileage);
7
    }
8
    
9
  private:
10
    FP_Attribute length    = {"Länge",  4.8, 0.1, 10.0};
11
    FP_Attribute width     = {"Breite", 2.0, 0.1, 10.0};
12
    FP_Attribute height    = {"Höhe",   1.6, 0.1,  3.0};
13
    
14
    FP_Attribute max_speed = {"Höchstgeschwindigkeit", 160.0, 10.0, 320.0};
15
    
16
    FP_Attribute mileage   = {"Kilometerleistung", 0.0,  0.0, 1'000'000.0};
17
};

Die Werte einzelner Attribute können sich ändern, die Bezeichnungen, 
Minimal-, Maximal- und Default-Werte bleiben jedoch immer konstant und 
werden lediglich für die Validierung von Eingaben, GUI-Ausgaben, etc. 
verwendet.

Und nun komme ich auch endlich zu der Problematik/Frage:
Jede Instanz von "Car" hält diese konstanten Werte redudant vor, was es 
zu vermeiden gilt. Gleichzeitig möchte ich eine möglichst einfache 
Syntax bei der Definition der einzelnen Klassen beibehalten und suche 
hier nach einer eleganten Lösung (es existieren knapp hundert 
verschiedene Klassen, die wiederum auch wieder bis zu 50 "Attribute" 
enthalten; auch existieren verschiedene Attribut-Typen mit 
unterschiedlichen Constraints, Datentypen, etc.).



Viele Grüße,
Peter

von lalala (Gast)


Lesenswert?

Mir ist die Frage nicht 100% klar, aber lösen vielleicht static member 
Variablen das Problem?
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
(und wenn sie sich nicht ändern sollen, vielleicht noch ein const davor)

von nicht"Gast" (Gast)


Lesenswert?

Moin,

wenn da Standarddaten sind, die sich nicht so oft ändern und für 
Validation benutzt werden, dann lager sie aus. Die müssen nicht 
unbedingt in der Klasse lagern. Schreib sie in eine separate Datei, die 
du einliest.

von micha (Gast)


Lesenswert?

Dein "Attribute_Set" enthält also Pointer/Referenzen zu den eigentlichen 
privaten Member-Variabeln? Was ist jetzt genau das Problem? Wenn nicht 
jede Instanz von "Car" eine eigene Kopie davon haben soll könntest Du 
sie "static" machen. Dann sollte jede Instanz auf die selben Daten 
zurückgreifen. Oder Du bastelst eine extra Klasse für diese 
Informationen und in "Car" dann eine Referenz darauf.

von Vincent H. (vinci)


Lesenswert?

Außer bei "length" und "witdh" seh ich da auf den ersten Blick nicht 
wahnsinnig viele doppelte Werte. Mal davon abgesehn sind wir hier im 
Forum "PC-Programmierung", selbst bei 100 Instanzen mit jeweils 50 
Attributen wären statische min/max float-Werte lediglich 40kBytes.

Ansonsten besteht natürlich jederzeit die Möglichkeit aus FP_Attribute 
ein Template zu machen und die min/max Werte als Typ zu übergeben und 
innerhalb der Klasse als statisch zu deklarieren. Jede Template-Instanz 
mit den selben Template-Parametern nutzt dann die selben statischen 
Werte.

Man beachte, dass ich oben von "Typ" und nicht von "float" gesprochen 
hab. Leider unterstützen Templates laut Standard keine Gleitkomma 
Parameter, weshalb man jedes min/max Paar in einen eigenen Typen wrappen 
müsste.

Vermutlich gibts noch schlauere Methoden... ad-hoc fällt mir aber grad 
keine ein. :)

von Rolf M. (rmagnus)


Lesenswert?

Ich denke, das Problem verstanden zu haben.
Dein FP_Attribute enthält Wert, Name, Minimum und Maximum. Für jedes 
Attribut sind die verschieden. Nun gibt es mehrere Instanzen von Car, 
die die gleichen Attribute haben, wo sich pro Car nur die Werte 
unterscheiden, aber in jedem Car haben sie die gleichen Namen, Minimum 
und Maximum.
Also so in etwa:

Car1 hat {"Länge",  4.8, 0.1, 10.0}
Car2 hat {"Länge",  4.2, 0.1, 10.0}
Car3 hat {"Länge",  4.3, 0.1, 10.0}
Car4 hat {"Länge",  3.9, 0.1, 10.0}

Und da für sämtliche Cars alles außer dem zweiten Element des Attributes 
immer gleich ist, willst du die Redundanz los werden.
Da würde mir nur einfallen, den Wert und die anderen Elemente des 
Attributs in zwei getrennte Klassen zu stecken und in der 
"Attribut-Werte"-Klasse dann auf die "Attribut-Eigenschaften"-Klasse zu 
referenzieren.
Die Variante von Vincent Hamp sollte auch gehen, hat aber den Nachteil, 
dass dann alle Attribute von unterschiedlichen Typen sind und man sie 
somit nicht mehr einfach in einen Container stecken und darüber 
iterieren kann.

PS: Welches Auto ist denn eigentlich nur 10 cm lang ;-)

: Bearbeitet durch User
von Peter (Gast)


Lesenswert?

Vielen Dank für die vielen Beiträge!
Ich war gerade dabei, das Problem etwas genauer zu beschreiben, habe 
jedoch eben gesehen, dass Rolf Magnus es sehr schön auf den Punkt 
gebracht hat. Genau darum ging es mir.


@Vicent Hamp
Das Problem sind in der Tat nicht die 100 Klassen und auch nicht die bis 
zu 50 "Attribut"-Member. Dies hatte ich nur erwähnt, um deutlich zu 
machen, dass die Definition der einzelnen Member möglichst simpel und 
übersichtlich geschehen sollte, so dass dies bei jeder Erweiterung oder 
neuen Klasse nicht in einer endloser Tipparbeit ausartet und die 
entsprechenden Constraints/Eigenschaften sofort ersichtlich sind.

Viel mehr werden die einzelnen Klassen viele tausend Male instanziert, 
so dass hier schon ein gewisser unnötiger Overhead zusammenkommt.

Der Ansatz mit den Templates war auch mein erster Gedanke, allerdings 
stößt man hier auch recht schnell an Grenzen, so dass weitere 
Workarounds notwendig sind. Ein Beispiel nanntest du ja mit den 
Gleitkomma-Parametern bereits.
Auch Strings (z.B. die Attribut-Namen) lassen sich nicht direkt als 
Template-Parameter übergeben, da diese "external linkage" benötigen, was 
den Code auch wieder weiter "zerfleddert".
Sollte es hier jedoch eine elegante Lösung geben, wäre ich diesem Ansatz 
nicht abgeneigt.




@Rolf Magnus
Dieser Ansatz gefällt mir auch sehr gut, zumal sich dies so gestalten 
ließe, dass das bisherige Interface nicht verändert werden müsste.
Ich werde dies einmal an einer konkreten Implementierung testen und mich 
dann noch einmal melden.


Viele Grüße,
Peter

Beitrag #5137512 wurde von einem Moderator gelöscht.
von Redundanz (Gast)


Lesenswert?

Ist doch gut, warum sollte man sie vermeiden? Letztlich wird die 
Software sicherer und die Ergebnisse plausibler.

Beitrag #5137919 wurde von einem Moderator gelöscht.
Beitrag #5137937 wurde von einem Moderator gelöscht.
Beitrag #5137939 wurde von einem Moderator gelöscht.
von zer0 (Gast)


Lesenswert?

Auf die Gefahr hin, mich unbeliebt zu machen: Wenn Du dort mit 
Meta-Daten über Attributen arbeiten musst und nicht ganz sicher bist, 
wie es nun für alle Zeit aussehen soll: Modelliere die Klassen in UML 
und generiere die Implementierungen der Daten- und Meta-Daten Klassen 
aus dieser Darstellung. Dann kannst du noch viel rumprobieren und bist 
auch in der Zukunft nicht festgelegt auf Lösungen, die ohne viel 
Schreibarbeit funktionieren.

Beitrag #5137956 wurde von einem Moderator gelöscht.
Beitrag #5138012 wurde von einem Moderator gelöscht.
Beitrag #5138091 wurde von einem Moderator gelöscht.
Beitrag #5138350 wurde von einem Moderator gelöscht.
Beitrag #5138517 wurde von einem Moderator gelöscht.
Beitrag #5139157 wurde von einem Moderator gelöscht.
Beitrag #5139985 wurde von einem Moderator gelöscht.
Beitrag #5140095 wurde von einem Moderator gelöscht.
Beitrag #5140239 wurde von einem Moderator gelöscht.
Beitrag #5140380 wurde von einem Moderator gelöscht.
Beitrag #5140401 wurde von einem Moderator gelöscht.
Beitrag #5140404 wurde von einem Moderator gelöscht.
Beitrag #5142597 wurde von einem Moderator gelöscht.
Beitrag #5143771 wurde von einem Moderator gelöscht.
Beitrag #5144996 wurde von einem Moderator gelöscht.
Beitrag #5145002 wurde von einem Moderator gelöscht.
Beitrag #5145230 wurde von einem Moderator gelöscht.
Beitrag #5145938 wurde von einem Moderator gelöscht.
Beitrag #5145965 wurde von einem Moderator gelöscht.
Beitrag #5148071 wurde von einem Moderator gelöscht.
Beitrag #5149298 wurde von einem Moderator gelöscht.
Beitrag #5149364 wurde von einem Moderator gelöscht.
Beitrag #5149384 wurde von einem Moderator gelöscht.
Beitrag #5153244 wurde von einem Moderator gelöscht.
Beitrag #5167779 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.