Forum: PC-Programmierung Objekte in Datei schreiben in C++


von Frager (Gast)


Lesenswert?

Hallo!

Ich programmiere aktuell ein kleines Programm in C++ (auf Linux, falls 
das wichtig ist).

Ich plane, eine Klasse "Schulklasse" anzulegen, in der es z.B. Variablen 
gibt wie "klassenvorstand", "klassensprecher", "raumNummer" und eine 
queue-Variable, die Objekte der Klasse "Schüler" speichert.

Die Klasse Schüler hat für sich dann wieder Variablen wie "Vorname", 
"Nachname", "Alter", etc.

Nun möchte ich das ganze Konstrukt in eine Datei abspeichern.

Wenn ich nun also ein Objekt habe mit dem Namen "Klasse_1A" (der in der 
queue-Variable z.B. 20 Objekte "Schüler" hat), wäre es toll, wenn es 
sowas geben würde wie
1
datei << Klasse_1A;

zum Abspeichern bzw.
1
datei >> Klasse_1A;

zum Auslesen aus der Datei.


Python hat doch soetwas mit "Pickle".

Gibt es soetwas auch für C++, das ähnlich einfach geht? Ein Beispiel 
wäre sehr nett!

Danke euch im Voraus!

von BOOMERang (Gast)


Lesenswert?

Gibt es. Nennt sich Operatoren überladen. Du musst für die Operatoren << 
und >> eben eine Funktion schreiben, so dass genau das passiert was du 
haben willst. Eventuell tut es auch eine Serialization/Deserialization 
Library.

von N. M. (mani)


Lesenswert?

BOOMERang schrieb:
> Serialization/Deserialization

Ist das richtige Stichwort.
Kann man selber schreiben falls es was spezifisches sein soll.
Ansonsten gibt es auch einige Libs die von Klasse zu z.B JSON, XML, usw 
wandeln und auch wieder zurück.

von Ergo70 (Gast)


Lesenswert?


von Frager (Gast)


Lesenswert?

Danke für die Hinweise!

Boost Serialization klingt relativ vielversprechend, was ich aber nicht 
ganz verstehe: Kann ich dann einfach die Klasse „Schulklasse“ 
serialisieren und die Objekte Schüler eines Objekts Klasse_1A werden 
gleich mit abgespeichert?
Oder muss ich das alles in jede Klasse implementieren?
Sieht irgendwie komplizierter aus, als ich es erhofft habe. Bei Python 
ging das doch ziemlich einfach…

von ich (Gast)


Lesenswert?

Frager schrieb:
> Danke für die Hinweise!
> Boost Serialization klingt relativ vielversprechend, was ich aber nicht
> ganz verstehe: Kann ich dann einfach die Klasse „Schulklasse“
> serialisieren und die Objekte Schüler eines Objekts Klasse_1A werden
> gleich mit abgespeichert?
> Oder muss ich das alles in jede Klasse implementieren?
> Sieht irgendwie komplizierter aus, als ich es erhofft habe. Bei Python
> ging das doch ziemlich einfach…

Müssen musst du nicht, bietet sich aber an.
Schwer ist es an sich nicht.
1. Operator überladen
2. Überlegen, was du wirklich speichern/laden willst und damit dann die 
Struktur in der Datei festlegen. Z.b. zuerst Klassenvorstand, dann 
Raumnummer, Anzahl Schüler, Liste mit Schülern,....
3. Evtl. Eine Version abspeichern, falls du die Dateistruktur Mal ändern 
solltest. Dann kann man beim laden basierend auf der Version die Datei 
unterschiedlich bearbei.

von res (Gast)


Lesenswert?

Wenn du kein Problem damit hast, einen Codegenerator zu verwenden, 
könnte
Googles "Protocol Buffers" eine einfache Serialization-Lösung für dein 
Problem sein.

https://developers.google.com/protocol-buffers/

von Tom (Gast)


Lesenswert?

nlohmann/json kann man sich auch mal ansehen, das ist relativ schmerzarm 
und fühlt sich nicht ganz so nach 2003 an wie boost, und json ist zum 
Rest der Welt kompatibel.

von Oliver S. (oliverso)


Lesenswert?

Qt bietet dafür auch Unterstützung.

Oliver

von Εrnst B. (ernst)


Lesenswert?

Statt da direkt mit irgendwelchen Bibliotheken loszulegen, wär's für den 
Lerneffekt vmtl. besser, ganz klassisch selber die ">>" und "<<" 
Operatoren zu überladen.

Auch zu Bedenken: du hast in der Klasse einen Schüler Klassensprecher 
und denselben Schüler auch nochmal in der Schülerliste.
Wenn du das stupide runterserialisierst, stehen diese Daten doppelt in 
der Datei. Beim Wiedereinlesen werden das dann zwei unterschiedliche 
Schüler-Objekte, die nur mit identischen Werten initialisiert worden 
sind.

von tut nix zur Sache (Gast)


Lesenswert?

Frager schrieb:
> Hallo!
>
> Ich programmiere aktuell ein kleines Programm in C++ (auf Linux, falls
> das wichtig ist).
>
> Ich plane, eine Klasse "Schulklasse" anzulegen, in der es z.B. Variablen
> gibt wie "klassenvorstand", "klassensprecher", "raumNummer" und eine
> queue-Variable, die Objekte der Klasse "Schüler" speichert.

Muss das wirklich eine Queue sein - ich würde eher ne std::set<Person> 
vorschlagen... (wobei ein Objekte der Klasse Person halt z.B. ein 
Schüler sein kann).

> Die Klasse Schüler hat für sich dann wieder Variablen wie "Vorname",
> "Nachname", "Alter", etc.
>
> Nun möchte ich das ganze Konstrukt in eine Datei abspeichern.

std::fstream kannste nehmen, aber selbst das speichern der struct/class 
mit fwrite/fread könnte gehen. Die coole Fancy-Lösung ist mit boost.

> Wenn ich nun also ein Objekt habe mit dem Namen "Klasse_1A" (der in der
> queue-Variable z.B. 20 Objekte "Schüler" hat),

Was spräche dagegen, wenn du einen std::set<Schulklasse> erzeugst, indem 
jedes 'Schulklasse'-Objekt eben eine std::set<Person> m_schueler 
enthält.

Google mal nach Entity/Relationship Modell, vielleicht hilft dir das.

von Rolf M. (rmagnus)


Lesenswert?

tut nix zur Sache schrieb:
> Muss das wirklich eine Queue sein - ich würde eher ne std::set<Person>
> vorschlagen... (wobei ein Objekte der Klasse Person halt z.B. ein
> Schüler sein kann).

Ein set ist für sowas in der Regel nicht sinnvoll. Eher ein vector.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> tut nix zur Sache schrieb:
>> Muss das wirklich eine Queue sein - ich würde eher ne std::set<Person>
>> vorschlagen... (wobei ein Objekte der Klasse Person halt z.B. ein
>> Schüler sein kann).
>
> Ein set ist für sowas in der Regel nicht sinnvoll. Eher ein vector.

Du meinst also, dieselbe Person könnte mehr als einmal in einer Klasse 
sein?

von Noch was (Gast)


Lesenswert?

Tja, ein Python Objekt enthält zur Laufzeit alle Informationen, die 
Pickle für die Serialisierung braucht. In einem kompilierten C++ 
Programm sind diese Informationen schlicht und einfach nicht mehr 
vorhanden.

So wird das halt aufwendig. Langfristig kommst du besser bei weg, wenn 
du dich in ein paar Generatoren und Frameworks einarbeitest. Im laufe 
der Zeit stößt du auf hunderte von Problemen. Die Frameworks sehen zwar 
unnötig komplex aus, aber die haben aber schon eine Lösung für diese 
unzähligen Probleme.

von Ergo70 (Gast)


Lesenswert?

Anstatt ganze Objekte in irgendwelchen Framework abhängigen 
Binarformaten zu speichern, könnte man die Daten auch in SQLite ablegen. 
Der Aufwand ist überschaubar und portabel ist es dann auch noch.

von J. S. (jojos)


Lesenswert?


von Karl Käfer (Gast)


Lesenswert?

Noch was schrieb:
> Tja, ein Python Objekt enthält zur Laufzeit alle Informationen, die
> Pickle für die Serialisierung braucht.

Ja... also, fast alle Informationen. Klar, für einfache Python-Instanzen 
geht es mithilfe des pickle-Moduls ganz einfach. Aber probier das mal 
mit dynamischeren Sachen, beispielsweise mit Instanzen, deren Methoden 
ihrerseits Funktionen oder Lambdas beinhalten. Da scheitert pickle sogar 
schon an recht einfachen Fällen und verschiedenen Builtin-Typen. 
Obendrein ist bei der Verwendung von pickle immer die Gefahr gegeben, 
daß nichtvertrauenswürdiger Code ausgeführt werden kann, siehe die große 
rot unterlegte Warnung oben in [1].

Etwas mehr als das builtin-Modul pickle kann das externe Modul dill 
serialisieren, das als Dropin-Ersatz für pickle gedacht ist und daher 
dieselbe API implementiert, aber ein bisschen mehr Funktionen bietet. 
Aber auch wenn dill einiges serialisieren kann, das pickle nicht 
schafft, ist das auch noch nicht der Weisheit letzter Schluß und 
scheitert an manchen Konstrukten, beispielsweise Tracebacks und -- für 
mich ganz besonders ärgerlich, wenngleich verständlich -- Generatoren. 
Die Beschränkungen zur Ausführung nichtvertrauenswürdigen Codes bestehen 
jedoch auch hier.

[1] https://docs.python.org/3/library/pickle.html

> So wird das halt aufwendig. Langfristig kommst du besser bei weg, wenn
> du dich in ein paar Generatoren und Frameworks einarbeitest.

Mein grundsätzlicher Rat wäre ein Serialisierungsformat, das auch mit 
anderen Sprachen verwendet werden kann. Da gibt es ja eine ganze Menge, 
JSON oder YAML beispielsweise, die sich auch gut komprimieren lassen -- 
oder Spezialisten wie Parquet, MessagPack, ProtoBuf oder Apache Thrift. 
Die haben zwar alle ihre ganz eigenen Limitierungen, aber zumindest 
kommt man auch mit anderen Sprachen an die serialisierten Inhalte, 
wenngleich das für ein Übungs-Spielprojekt wie das des TO vermutlich 
keine hohe Priorität hat.

von Karl Käfer (Gast)


Lesenswert?

J. S. schrieb:
> Python ist aber nicht grün.
>
> 
https://www.heise.de/news/Gruenes-Programmieren-C-und-Rust-energieeffizient-Python-und-Perl-Schlusslicht-7259319.html

Oho, sieh an, interpretierte Programme kosten mehr Laufzeit und Speicher 
als kompilierte, was für eine Überraschung... nicht. Den 
Energieverbrauch bei der Entwicklung haben diese Wissenschaftler auch 
einfach mal ignoriert, lol.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Du meinst also, dieselbe Person könnte mehr als einmal in einer Klasse
> sein?

Definiere "dieselbe Person", bzw. musst du definieren, wie man erkennt, 
ob eine Person "kleiner" ist als eine andere im Sinne einer 
Sortierreihenfolge. Dann kann man mit einem set effizient überprüfen, ob 
eine Person, die nach genau diesen Kriterien die selbe ist, bereits 
vorhanden ist. Ansonsten bietet das set aber keinen Vorteil.

von Noch was (Gast)


Lesenswert?

> ein Serialisierungsformat, das auch mit
> anderen Sprachen verwendet werden kann

Das hat sich nicht bewährt. Von Corba bis SOAP. Immer wieder das selbe 
Problem. Wenn das Format alle Features bietet, wird es unbrauchbar 
komplex. Bei einfachen Formaten musst du sowieso einen Mapper schreiben. 
Kannst nur die Daten aus dem JSON benutzen, nicht die kompletten 
Objekte.

Wenn du ein System aus mehreren Programmen in mehreren 
Programmiersprachen baust, brauchst du normalerweise sowieso mehrere 
Objektmodelle. In Summe hast du weniger Arbeit, wenn du traditionelle 
Datenbanktabellen benutzt. Jedes Programm mappt die Daten auf seine 
eigene Objektstruktur.

von Ein T. (ein_typ)


Lesenswert?

Noch was schrieb:
> Das hat sich nicht bewährt. Von Corba bis SOAP.

Bei CORBA und SOAP geht es primär um Remote Procedure Calls in 
Netzwerken, nicht um die Serialisierung von Objekten in Dateien.

CORBA und SOAP Enterprise-Umfeld sind weit verbreitet. In anderen 
Bereichen werden derartige Technologien nicht so oft benötigt, häufig 
stehen auch domänenspezifische Alternativen wie etwa OpenMP oder Spark 
zur Verfügung.

Insofern fürchte ich, daß Dein Einwand inhaltlich nicht zutrifft und 
obendrein leider am Thema dieses Threads vorbeigeht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Du meinst also, dieselbe Person könnte mehr als einmal in einer Klasse
>> sein?
>
> Definiere "dieselbe Person",

Das muss der TO machen, nicht ich.

> bzw. musst du definieren, wie man erkennt,
> ob eine Person "kleiner" ist als eine andere im Sinne einer
> Sortierreihenfolge.

Der operator< wird wie üblich verwendet, um zu prüfen, ob Gleichheit 
oder Ungleichheit vorliegt. Im Sinne des TO ggf. einfach so etwas wie 
eine "Schülernummer".

> Dann kann man mit einem set effizient überprüfen, ob
> eine Person, die nach genau diesen Kriterien die selbe ist, bereits
> vorhanden ist. Ansonsten bietet das set aber keinen Vorteil.

Das set (Menge) ist eben genau die Datenstruktur, um den Sachverhalt 
einer Klasse (eine Menge von Personen - im mathematischen Sinne) zu 
modellieren. Datenstrukturen sind so zu wählen, dass sie den zu 
modellierenden Sachverhalt (möglichst) genau abbilden.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Rolf M. schrieb:
>> Wilhelm M. schrieb:
>>> Du meinst also, dieselbe Person könnte mehr als einmal in einer Klasse
>>> sein?
>>
>> Definiere "dieselbe Person",
>
> Das muss der TO machen, nicht ich.

Nun, du hast den Begriff ins Spiel gebracht.

>> bzw. musst du definieren, wie man erkennt,
>> ob eine Person "kleiner" ist als eine andere im Sinne einer
>> Sortierreihenfolge.
>
> Der operator< wird wie üblich verwendet, um zu prüfen, ob Gleichheit
> oder Ungleichheit vorliegt. Im Sinne des TO ggf. einfach so etwas wie eine
> "Schülernummer".

Oder ein dem set übergebener Funktor. Ich würde da auch keinen 
programmweiten Vergleichsoperator für so eine Struktur haben wollen, der 
nur ein einzelnes Element davon vergleicht. Da diese Operation so nur 
für das set benötigt wird und ansonsten eher wenig sinnvoll ist, gehört 
sie auch nur dort hin.

>> Dann kann man mit einem set effizient überprüfen, ob
>> eine Person, die nach genau diesen Kriterien die selbe ist, bereits
>> vorhanden ist. Ansonsten bietet das set aber keinen Vorteil.
>
> Das set (Menge) ist eben genau die Datenstruktur, um den Sachverhalt
> einer Klasse (eine Menge von Personen - im mathematischen Sinne) zu
> modellieren.

Diese Beschreibung trifft auf die meisten Standard-Container zu. Was 
zeichnet da das set jetzt speziell aus?

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Rolf M. schrieb:
>>> Wilhelm M. schrieb:
>>>> Du meinst also, dieselbe Person könnte mehr als einmal in einer Klasse
>>>> sein?
>>>
>>> Definiere "dieselbe Person",
>>
>> Das muss der TO machen, nicht ich.
>
> Nun, du hast den Begriff ins Spiel gebracht.

Ja, ich ich muss nicht die Semantik definieren!

>
>>> bzw. musst du definieren, wie man erkennt,
>>> ob eine Person "kleiner" ist als eine andere im Sinne einer
>>> Sortierreihenfolge.
>>
>> Der operator< wird wie üblich verwendet, um zu prüfen, ob Gleichheit
>> oder Ungleichheit vorliegt. Im Sinne des TO ggf. einfach so etwas wie eine
>> "Schülernummer".
>
> Oder ein dem set übergebener Funktor. Ich würde da auch keinen
> programmweiten Vergleichsoperator für so eine Struktur haben wollen, der
> nur ein einzelnes Element davon vergleicht. Da diese Operation so nur
> für das set benötigt wird und ansonsten eher wenig sinnvoll ist, gehört
> sie auch nur dort hin.

Ich denke, sie wird auch sonst benötigt, z.B. um sich eben eine Liste 
alle Schüler in natürlicher Reihenfolge auszugeben.

>>> Dann kann man mit einem set effizient überprüfen, ob
>>> eine Person, die nach genau diesen Kriterien die selbe ist, bereits
>>> vorhanden ist. Ansonsten bietet das set aber keinen Vorteil.
>>
>> Das set (Menge) ist eben genau die Datenstruktur, um den Sachverhalt
>> einer Klasse (eine Menge von Personen - im mathematischen Sinne) zu
>> modellieren.
>
> Diese Beschreibung trifft auf die meisten Standard-Container zu. Was
> zeichnet da das set jetzt speziell aus?

Du weißt nicht, was das Kennzeichen einer Menge (mathematisch) ist?

von db8fs (Gast)


Lesenswert?

Rolf M. schrieb:
>>> Dann kann man mit einem set effizient überprüfen, ob
>>> eine Person, die nach genau diesen Kriterien die selbe ist, bereits
>>> vorhanden ist. Ansonsten bietet das set aber keinen Vorteil.

Na ja, ne std::set ist auch sortiert. Wenn man also den Funktor 
überschreibt bzw. ein Prädikat definiert, sind alle in der set 
gespeicherten Elemente (z.B. hier Schüler) gleich nach Vor- und 
Nachnamen sortiert. Auswerten sollte der doch das Prädikat höchstens 
beim Einfügen in die set.

>> Das set (Menge) ist eben genau die Datenstruktur, um den Sachverhalt
>> einer Klasse (eine Menge von Personen - im mathematischen Sinne) zu
>> modellieren.
>
> Diese Beschreibung trifft auf die meisten Standard-Container zu. Was
> zeichnet da das set jetzt speziell aus?

Ganz schlecht ist die Idee mit der set nicht. Es wurde oben irgendwas 
mit E/R Diagramm erwähnt - in der UML2 sind Multiplizitäten mehrerer 
Objekte (quasi Container) definiert per default als {unordered, unique}. 
Also als unordered_set - gar nicht soweit weg. Und der Nutzen der 
sortierten Speicherung ist für so nen Anwendungsfall wie hier auch 
irgendwo da.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
>> Nun, du hast den Begriff ins Spiel gebracht.
>
> Ja, ich ich muss nicht die Semantik definieren!

Nun, wenn du Begriffe in der Diskussion einbringst, wäre es schon 
logisch, wenn du und nicht jemand anders definiert, was du damit meinst.

>> Oder ein dem set übergebener Funktor. Ich würde da auch keinen
>> programmweiten Vergleichsoperator für so eine Struktur haben wollen, der
>> nur ein einzelnes Element davon vergleicht. Da diese Operation so nur
>> für das set benötigt wird und ansonsten eher wenig sinnvoll ist, gehört
>> sie auch nur dort hin.
>
> Ich denke, sie wird auch sonst benötigt, z.B. um sich eben eine Liste
> alle Schüler in natürlicher Reihenfolge auszugeben.

Auch hier wieder die Frage: Was verstehst du unter der natürlichen 
Reihenfolge von Personen? Für die Ausgabe will ich in der Regel nach 
verschiedenen Kriterien sortieren können und nicht eine bestimmte 
Sortierreihenfolge hardcoded im Programm stehen haben.

> Du weißt nicht, was das Kennzeichen einer Menge (mathematisch) ist?

Eine Menge hat keine besondere Ordnung und braucht daher keinen 
Vergleich der Elemente miteinander, wie es ein std::set benötigt.

db8fs schrieb:
> Na ja, ne std::set ist auch sortiert. Wenn man also den Funktor
> überschreibt bzw. ein Prädikat definiert, sind alle in der set
> gespeicherten Elemente (z.B. hier Schüler) gleich nach Vor- und
> Nachnamen sortiert.

Ja, das ist ein Vorteil bei Nutzung eines set. Das geht aber auch nur, 
wenn einem genau eine Sortierung ausreicht. Wenn ich stattdessen nach 
Alter sortiert ausgeben will, muss ich den Inhalt in einen neuen 
Container kopieren und umsortieren.

von db8fs (Gast)


Lesenswert?

Rolf M. schrieb:
> Ja, das ist ein Vorteil bei Nutzung eines set. Das geht aber auch nur,
> wenn einem genau eine Sortierung ausreicht. Wenn ich stattdessen nach
> Alter sortiert ausgeben will, muss ich den Inhalt in einen neuen
> Container kopieren und umsortieren.

Stimmt. Musste aber auch sehen, dass Datenhaltung und 
Ausgabeformatierung meistens aus sehr guten Gründen getrennt gemacht 
werden. Und ne set zu traversieren, da biste glaube ich bei 
logarithmischen Zugriff pro Element. Bei so „Popelkram“ mit mal 
höchstens 30 Elementen im Container drinne, ist das doch näherungsweise 
Konstantzeit beim lesen. Auch der lexikographische Vergleich für den 
überschriebenen operator<() beim insert spielt kaum ne Rolle - wie 
gesagt, bei großen Multiplizitäten sieht’s anders aus.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>>> Nun, du hast den Begriff ins Spiel gebracht.
>>
>> Ja, ich ich muss nicht die Semantik definieren!
>
> Nun, wenn du Begriffe in der Diskussion einbringst, wäre es schon
> logisch, wenn du und nicht jemand anders definiert, was du damit meinst.

Ich hatte oben einen Vorschlag gemacht, den Du offensichtlich überlesen 
hast: Schülernummer.

>> Ich denke, sie wird auch sonst benötigt, z.B. um sich eben eine Liste
>> alle Schüler in natürlicher Reihenfolge auszugeben.
>
> Auch hier wieder die Frage: Was verstehst du unter der natürlichen
> Reihenfolge von Personen? Für die Ausgabe will ich in der Regel nach
> verschiedenen Kriterien sortieren können und nicht eine bestimmte
> Sortierreihenfolge hardcoded im Programm stehen haben.

Als natürliche Ordnung wird im (C++) Jargon die Anwendung des 
operator<() als Ordnungsrelation verstanden (das allg. template 
std::less verwendet operator<()).

>> Du weißt nicht, was das Kennzeichen einer Menge (mathematisch) ist?
>
> Eine Menge hat keine besondere Ordnung und braucht daher keinen
> Vergleich der Elemente miteinander, wie es ein std::set benötigt.

Du hast den Punkt leider nicht verstanden: ein std::set modelliert eine 
Menge im mathematischen Sinn. Deswegen heißt der DT auch so. In einer 
Menge kommen Elemente nur genau {0,1}-mal vor bzw. es geht nur darum, ob 
eine Element enthalten ist oder nicht. Dazu muss man Elemente auf 
Gleichheit prüfen können (Ausgedrückt im Compare-Requirement von 
std::set). Und dazu wiederum verwendet std::set<> dann std::less<>() 
(und damit den operator<()), wobei es bei der Anwendung primär nicht um 
die Ordnung geht, sondern um Gleicheit, die auf "<" zurückgeführt wird: 
!(a < b) && !(b < a). Da in der Praxis std::set mit einem Binärbaum 
(RB-Tree) realisiert wird (Performance), wird std::less<>() auch dafür 
gebraucht.
Im Gegensatz dazu gibt es auch die Multimenge als std::multiset. Hier 
können gleiche Elemente mehrfach vorkommen.
Aber das ist eigentlich gar nicht mein Punkt von oben gewesen. Sondern 
mir ging es um die Modellierung des Sachverhaltes Schulklasse. Und eine 
Schulklasse ist eine echte Menge von Schülern: ein bestimmter Schüler 
kommt in einer Klasse nur {0,1}-mal vor. Und die Prüfung auf Gleichheit 
kann std::set in log. Zeit durchführen (bzw. alle Operationen, die auf 
op<() beruhen). Daher ist std::set sowohl semantisch wie auch technisch 
zunächst die richtige Datenstruktur (und wie immer: natürlich kann es 
Argumente dagegen geben, jedoch sind die bisher nicht vom TO genannt 
worden).

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
>> Nun, wenn du Begriffe in der Diskussion einbringst, wäre es schon
>> logisch, wenn du und nicht jemand anders definiert, was du damit meinst.
>
> Ich hatte oben einen Vorschlag gemacht, den Du offensichtlich überlesen
> hast: Schülernummer.

Ich hatte es ursprünglich gesehen, aber dann nicht mehr wiedergefunden 
und wusste auch nicht mehr, von wem es kam. Hab aber auch nach ID statt 
nach Schülernummer gesucht, und beim schnellen drüberschauen hat mein 
Parser wohl einen Schülernamen draus gemacht. :)
Wie dem auch sei, wird die Schülernummer aber auch nicht garantieren, 
dass jemand den selben Schüler nicht mit einer neuen Nummer noch ein 
zweites mal hinzufügt. Es garantiert nur die Einmaligkeit der Nummer, 
nicht die des "kompletten" Schülers.

> Du hast den Punkt leider nicht verstanden: ein std::set modelliert eine
> Menge im mathematischen Sinn. Deswegen heißt der DT auch so. In einer
> Menge kommen Elemente nur genau {0,1}-mal vor bzw. es geht nur darum, ob
> eine Element enthalten ist oder nicht. Dazu muss man Elemente auf
> Gleichheit prüfen können (Ausgedrückt im Compare-Requirement von
> std::set).

Das funktioniert für einfache Datentypen gut, weil "Gleichheit" sich 
dort auf den kompletten Inhalt bezieht, aber bei Strukturtypen bezieht 
sie sich in der Regel (z.B. bei deiner Schülernummer) nur auf ein 
Element der Struktur. Das ist für mich dann eher eine 
Key/Value-Zuordnung mit der Schülernummer als Key und dem Rest, der 
nicht in den Vergleich eingeht, als Value. Das wäre dann aber eher eine 
std::map.

von db8fs (Gast)


Lesenswert?

Rolf M. schrieb:
> Wie dem auch sei, wird die Schülernummer aber auch nicht garantieren,
> dass jemand den selben Schüler nicht mit einer neuen Nummer noch ein
> zweites mal hinzufügt. Es garantiert nur die Einmaligkeit der Nummer,
> nicht die des "kompletten" Schülers.

Na ja, er hat schon irgendwo recht - die Schülernummer kannste ja als 
Art Primärschlüssel sehen. Kann ja auch zwei Leute mit dem selben Namen 
geben. Ich stimm dir aber zu, dass das Vergleichsprädikat eigentlich so 
gebaut sein müsste, dass es alle Felder der Struktur miteinander 
vergleicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>>> Nun, wenn du Begriffe in der Diskussion einbringst, wäre es schon
>>> logisch, wenn du und nicht jemand anders definiert, was du damit meinst.
>>
>> Ich hatte oben einen Vorschlag gemacht, den Du offensichtlich überlesen
>> hast: Schülernummer.
>
> Ich hatte es ursprünglich gesehen, aber dann nicht mehr wiedergefunden
> und wusste auch nicht mehr, von wem es kam. Hab aber auch nach ID statt
> nach Schülernummer gesucht, und beim schnellen drüberschauen hat mein
> Parser wohl einen Schülernamen draus gemacht. :)
> Wie dem auch sei, wird die Schülernummer aber auch nicht garantieren,
> dass jemand den selben Schüler nicht mit einer neuen Nummer noch ein
> zweites mal hinzufügt. Es garantiert nur die Einmaligkeit der Nummer,
> nicht die des "kompletten" Schülers.

Das ist ein grundsätzliches Problem und hat nichts damit zu tun, ob 
jetzt ein std::set<> oder ein anderer Container eingesetzt wird. Der TO 
muss die Gleichheit definieren, wenn er es mit den anderen Attributen 
macht und/oder keine Schülernummer verwendet, ist das auch ok.

>> Du hast den Punkt leider nicht verstanden: ein std::set modelliert eine
>> Menge im mathematischen Sinn. Deswegen heißt der DT auch so. In einer
>> Menge kommen Elemente nur genau {0,1}-mal vor bzw. es geht nur darum, ob
>> eine Element enthalten ist oder nicht. Dazu muss man Elemente auf
>> Gleichheit prüfen können (Ausgedrückt im Compare-Requirement von
>> std::set).
>
> Das funktioniert für einfache Datentypen gut, weil "Gleichheit" sich
> dort auf den kompletten Inhalt bezieht, aber bei Strukturtypen bezieht
> sie sich in der Regel (z.B. bei deiner Schülernummer) nur auf ein
> Element der Struktur. Das ist für mich dann eher eine
> Key/Value-Zuordnung mit der Schülernummer als Key und dem Rest, der
> nicht in den Vergleich eingeht, als Value. Das wäre dann aber eher eine
> std::map.

Von mir aus auch eine std::map. Und auch dort darf der Schlüsselwert nur 
{0,1}-mal vorkommen. Der technische Unterschied zu std::set<> ist 
marginal.

Wie (!) der op<() realisiert wird,  ist letztlich ein Detail, was der TO 
für sich sinnvoll lösen muss. Wichtig war mir zu betonen, dass ein 
Klasse eben eine Menge (mathematisch) ist: derselbe Schüler kann nicht 
zweimal in der Klasse sein.

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.