PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++: Wie legt Objekte einer Klasse dynamisch Stück für Stück, also nach und nach, an?


Gast
2007-10-06, 04:21:32
Wie legt man dynamisch ein Array von Objekten an,
wenn die Anzahl der letzten endes benötigten Objekte noch gar nicht bekannt ist?


Bsp. ich habe eine Klasse Namens "Person".
Diese Klasse enthält den Vornamen und Nachnamen der Person als Werte.

Und jetzt will ich in meiner main Methode Objekte der Klasse vom Typ Person initalisieren.
Aber wieviele Objekte der Klasse Person erstellt werden sollen, wird erst zur Laufzeit des Programms bekannt und das nicht auf einmal, sondernn nur Häppchenweise.

So etwas:


int anzah = 0;
cout << "Wieviele personen sind es? << endl;
cin >> anzahl;


Person *objekte = new Person[anzahl];
...



Sollte es also nicht sein, da die Anzahl ja nicht auf einen Schlag bekannt ist.


Es sollte eher etwas in der Art sein:



// Pseudocode:

int anzahl = 0;
string vorname, nachname;
char input;
bool fertig = false;
Person *objekte;

while (fertig == false)
{
anzahl++;
cout << endl << anzahl << ". Person" << endl;
cout << "---------------------------" << endl;
cout << "Vorname: ";
cin >> vorname;
cout << endl << "Nachname: ";
cin >> nachname;
// Pseudocode:
Füge ein neues Objekt dem Array *objekte vom Typ Person hinzu und initalisiere mit (Vorname, nachname);
cout << "Noch eine Person (j/n)?";
if ((cin >> input) = 'n')
{
fertig = true;
}
}



Hier wird laut Pseudocode ein Objekt dem Array nach und nach hinzugefügt,
solange der Benutzer auf die Frage "noch eine Person" mit ja beantwortet.

Wieviele Objekte insgesamt also erzeugt werden sollen, ist die ganze Zeit über noch offen.
Und so etwas würde ich gerne realisiert haben, wie mache ich das?

Gast
2007-10-06, 04:22:33
Ups, in der Überschrift fehlt noch das wort "man", könnte das ein Mod eventuell noch hinzufügen?

Es sollte folgendes in der Überschrift stehen:


C++: Wie legt man Objekte einer Klasse dynamisch Stück für Stück, also nach und nach, an?

Gast
2007-10-06, 10:02:38
Nimm dafür einen vector oder eine ähnliche Datenstruktur.

Gast
2007-10-06, 10:12:38
Nimm dafür einen vector oder eine ähnliche Datenstruktur.


Und wie erweitere ich den Vektor?

Person *objekte = *objekte + 1;

Kann es ja wohl nicht sein, da schreibt der Vektor ja sonstwohin.

Gast
2007-10-06, 11:35:13
so in etwa:


#include <vector>
using namespace std;

...

vector<Person> objekte;

objekte.push_back(new Person(...));

Trap
2007-10-06, 12:00:54
Das Konzept ist immer das gleiche:
Wenn das Array voll ist ein größeres neues anlegen und das schon benutzte dort an den Anfang kopieren.

Ectoplasma
2007-10-06, 12:07:57
Wenn die Anzahl von Objekten für einen Vektor nicht bekannt ist, dann legt man ein wenig Speicher für eine Menge n von Objekten an. Ist dieser Speicher voll, dann realloziert man den alten Speicher, jetzt aber mit der doppelten Menge an Objekten.

Nun muss man sich fragen, wie das gehen kann. Wenn man beispielsweise Speicher für 10 Objekte anlegt, aber zunächst nur ein Objekt in einen Vektor packt, was geschieht dann mit den restlichen 9 Objekten. Wurden von diesen Objekten die Konstruktoren durchlaufen und werden anschließend wieder die Destruktoren durchlaufen?

Die Antwort ist ja, wenn man den Vector auf diese Weise anlegt:


MyObject *pMyObjects = new MyObject[10];

delete []pMyObjects;


Aber möchte ich das? Die Antwort lautet nein! Es gibt in C++ einen Trick, wie man Speicher für Objekte anlegt, diese aber nicht konstruiert. In C++ kann man Objekte nachträglich auf bereits allozierten Speicher konstruieren.

Das sieht dann so aus:


MyObject *pMyObjects = (MyObject *)malloc(10 * sizeof(MyObject));

// create an element at position 0
new(1, pMyObjects) MyObject;

// or create an element at position 1
new(1, pMyObjects + 1) MyObject;

// destroy an element at position 0
pMyObjects->~MyObject();

// destroy an element at position 1
(pMyObjects + 1)->~MyObject();

// delete vector
free(pMyObjects);


Auf diese Weise arbeitet auch die Standard Template Library. Oben habe ich das allerdings sehr schematisch dargestellt.

Gast
2007-10-06, 12:08:37
Das Konzept ist immer das gleiche:
Wenn das Array voll ist ein größeres neues anlegen und das schon benutzte dort an den Anfang kopieren.

Da steigt der Aufwand aber enorm, wenn ich wegen jedem neuen Objekt, ein komplettes Array auf ein neues Array+1 umkopieren muß.


Nehmen wir mal an ich habe 100000 Objekte und somit auch ein Array von Zeigern dieser Größe um auf diese Objekte zu verweisen.
Und jetzt kommt ein Objekt hinzu.
Ich brauche also ein neues Array mit 100001 Speicherplätzen und muß den Inhalt des alten Arrays dort hinzukopieren.

Und das mache ich jedesmal, sobald ein Objekt hinzugefügt wird.


Geht das wirklich nicht performanter?

Ok, ich könnte das nächste Array gleich um 100 Plätze größer machen,
das senkt die Anzahl der Umkopierereischritte, aber geht das nicht noch eleganter?

Trap
2007-10-06, 12:21:56
Geht das wirklich nicht performanter?

Ok, ich könnte das nächste Array gleich um 100 Plätze größer machen,
das senkt die Anzahl der Umkopierereischritte, aber geht das nicht noch eleganter?
Normalerweise nimmt man nicht n+x sondern n*x, das gibt asymptotisch eine bessere Laufzeitkomplexität.

Wenn man auf die im Speicher aufeinanderfolgenden Elemente verzichten kann ist das besser:
http://citeseer.ist.psu.edu/brodnik99resizable.html (gibt es auch fertig als Bibliothek)

Gast
2007-10-08, 07:46:04
Danke an alle.
Ich habe es jetzt dank euch verstanden. :)

Mein C++ Buch war da etwas irreführend,
dort wurde in einem Kapitel von dynamischen Feldern und Vektoren für Objekte gesprochen und auch ständig das Wort Vektor verwendet, aber einen Hinweis ein paar Kapitel weiter auf "den" Vektor, also die Container der STL der "die" Lösung für mein Problem ist, gab es leider nicht.
Daher habe ich auch nicht gleich verstanden, was der 1. Gast mit vector mir sagen will, da der Autor des Buches mit Vektor auch normale primitive Zeiger meint.

SGT.Hawk
2007-10-10, 07:54:32
Ich würde eine verkette Liste programmieren, da brauchst du auch nicht die Länge angeben.

Coda
2007-10-10, 20:50:42
Dann nimmt man besser std::list

Nasenbaer
2007-10-10, 21:51:04
Hier die vn std:list zur Verfügung gestellten Methoden, dann brauchst du nicht lange suchen: http://www.sgi.com/tech/stl/List.html