Dynamisches Objekt sauber erzeugen
-
Übrigens, dein erster Versuch wäre falsch gewesen, nur so als Hinweis :p
-
Dacht ich mir.
Eventuell unabhängig davon, aber im Zuge der Arbeiten mit std::vector sagt mir der Debugger:Eine Ausnahme (erste Chance) bei 0x7770dcbb in planer.exe: 0xC0000374: Ein Heap wurde beschädigt.
Unbehandelte Ausnahme bei 0x7770dcbb in planer.exe: 0xC0000374: Ein Heap wurde beschädigt.Leider ohne Zeilenangabe o.ä. Was bedeutet das "Ein Heap wurde beschädigt"?
Gruß, Julian
-
mit
Kurse *kurse = new Kurse;hast du einmal Speicher angefordert, wo einmla Kurse reinpasst. Möchtest mehrere Kurse, z.B. müsst das tun
Kurse *kurse = new Kurse [10]; // allgemeiner Kurse *kurse = new Kurse [irgende anzahl];Jetzt hast du Platz für 10 Kurse.
Dynamisch ist das in dem Sinne das zur Laufzeit entscheiden kannst wie groß dein Kurse Array ist. Einmal allociert allerdings ist die Größe fest, und erweitert sich nicht automatisch, falls du dich danach entscheidest mehr Kurse zu speichernfreigeben tust du den Speicher mit
delete [] kursedie Anzahl brauchst du hier nich angeben.
So nachdem man ihm das erklärt hat, kann man jetz sagen.
Schau dir mal lieber std::vector an !
MfG
-
Hast du jetzt immer noch irgendwo ein "new" im Code? Solltest du eigentlich mit std::vector nicht mehr brauchen. Zeig mal deinen Code.
-
shizzophate schrieb:
Eventuell unabhängig davon, aber im Zuge der Arbeiten mit std::vector sagt mir der Debugger:
Eine Ausnahme (erste Chance) bei 0x7770dcbb in planer.exe: 0xC0000374: Ein Heap wurde beschädigt.
Unbehandelte Ausnahme bei 0x7770dcbb in planer.exe: 0xC0000374: Ein Heap wurde beschädigt.Leider ohne Zeilenangabe o.ä. Was bedeutet das "Ein Heap wurde beschädigt"?
Du hast wahrscheinlich irgendwelche Speicherstellen modifiziert, die Dir gar nicht gehörten, und damit scheinbar Datenstrukturen zerstört, die für die Verwaltung des Freispeichers verwendet wird. Demjenigen, der den Speicher verwaltet ist dies aufgefallen und hat dafür gesorgt, dass das Programm terminiert wird. Du hast quasi noch Glück gehabt, dass Dein Computer nicht explodiert ist!

Tipp1: Verwende Datenstrukturen aus der Standardbibliothek, sofern möglich.
Tipp2: Verwende den Debug-Modus dieser Bibliothek, um Fehler früher erkennen zu können (siehe dazu in der Dokumnetation Deines Compilers nach).C und C++ ist nunmal kein "Baby-Spielzeug". Es ist spitz und man kann sich damit das Auge ausstechen, wenn man nicht weiß, was man da tut.
-
krümelkacker schrieb:
Du hast quasi noch Glück gehabt, dass Dein Computer nicht explodiert ist!

Vorsicht mit solchen Scherzen, nachher glaubt das noch jemand.

-
Vielen Dank für die Erklärungen. Das deckt sich mit dem, was ich heute Nacht noch zu den Themen "Heap" und "dynamische Objekte" gelesen habe, obwohl ich das Problem des beschädigten Heaps nicht wirklich greifen kann - dazu fehlt mir ein ganzes Stück Theorie/Wissen, aber ich sehe ein, dass der Fehler an mir liegt

Neben der Klasse "Kurse" habe ich noch 2 weitere Klassen "Schueler" und "Lehrer". Da ich jetzt weiß, dass ich dynamische Objekte dann verwende, wenn die Größe selbigen Objekts erst zur Laufzeit feststeht, erzeuge ich also zur Laufzeit so viele "Schueler" und "Lehrer", wie Eintraege im jeweiligen Verzeichnis sind:
Schueler *schueler = new Schueler[EintraegeCnt("datenbank\\schueler\\*.sch")]; Lehrer *lehrer = new Lehrer[EintraegeCnt("datenbank\\lehrer\\*.leh")];Mutet auch etwas improvisiert an, funktioniert aber.
Jetzt gilt es für mich, einen Algorithmus zu finden, der nach und nach alle Schueler abarbeitet und in Kurse "steckt" und danach den Kursen Lehrer zuordnet.
Die Anzahl der Kurse ist vorerst unbekannt, ABER:
ich kann ähnlich wie mit den Schülern und Lehrern eine Funktion schreiben, die kurz checkt, wieviele Schüler welches Fach gewählt haben und als return-Wert die sich daraus ergebende Anzahl an Kursen zurückgeben um damit ebenfalls ein dynamisches Objekt der ArtKurse *kurse = new Kurse[ZaehleKurse(schueler)]; // alle schueler übergebenzu erzeugen.
Hab's auch probiert:int ZaehleKurse(Schueler[]); // Prototyp int ZaehleKurse(Schueler schueler[]) { // <-- Hier zeigt der Debugger hin und meckert int cnt=0, kursNr, kurse[19]; // [...] die Anzahl der Kurse wird ermittelt return cnt; }wenn ich zu Testzwecken die Funktion erstmal so aufrufe, bekomme ich als Return-Wert auch tatsächlich die korrekte Anzahl an Kursen, jedoch eben mit Unterbrechung durch den Debugger. Es kommt kein Fehler, keine "Heap-Beschädigung" - nur eine "Aufrufliste", wo er auf die obige Zeile zeigt und mir aus der "crtexec.c" die Stelle zeigt:
__initenv = envp; mainret = main(argc, argv, envp);Mache ich irgendwas falsch? Darf man dynamische Objekte nicht einfach so als Parameter übergeben?
Oder würdet ihr mir, auch wenn ich berechnen kann, wieviele Kurse/Lehrer/Schüler es zur Laufzeit gibt, trotzdem zu vectoren raten?Danke für die hilfreichen Tips nochmal
, Julian
-
Woher weiß denn deine "ZaehleKurse" Funktion überhaupt wie viele Schüler es gibt?
Und std::vector<Schueler>/std::vector<Lehrer> wäre immer noch schöner.
-
Allerdings kannst du dann den std::vector so erstellen:
std::vector<Schueller> schueller(EintraegeCnt("datenbank\\schueler\\*.sch") );Dadurch macht der Vektor eigentlich genau das selbe was du machst, mit dem Unterschied das er einfacher zu handhaben ist und sich auch noch nachträglich vergrößern kann.
-
Wieviele Schüler es gibt wissen alle:
class Schueler { public: Schueler(); static int schueler_cnt; }; int Schueler::schueler_cnt=0; Schueler::Schueler() { id = schueler_cnt; Schueler::schueler_cnt++; }mit "Schueler::schueler_cnt"
Der ganze Code ist natürlich etwas länger, aber bevor ich meinen ganzen code rechtfertigen muss, habe ich nur die wesentlichen Teile kopiert. Die Sachen funktionieren im Grunde ja auch und für 2 Jahre Grundkurs Informatik (ein bisschen rumscripten mit python) können die Prüfer von mir bei weitem nicht das erwarten, was ein erfahrener Programmierer schreiben würde.Ich würde aber gerne wissen, warum es "schöner" ist, std::vector<> zu verwenden. Welche Vorteile haben sie gegenüber meinem dynamischen Objekt in meinem konkreten Fall (bevor ich jetzt einfach wieder ins kalte Wasser springe)?
Das Problem vom Debugger bleibt...
Gruß
-
shizzophate schrieb:
Ich würde aber gerne wissen, warum es "schöner" ist, std::vector<> zu verwenden. Welche Vorteile haben sie gegenüber meinem dynamischen Objekt in meinem konkreten Fall
Das Prinzip von RAII ist eigentlich, dass du keine Speicheranforderungen außerhalb von Klassen hast. Das bedeutet, dass die unterste "Instanz" immer auf dem Stack liegt, und das wiederrum bedeutet, dass deren Destruktor am Ende des Gültigkeitsbereichs sicher aufgerufen wird. Kurzum: Der vector garantiert dir ein sicheres delete[]. Zudem Methoden wie .resize() und .push_back().
Zu der statischen Schüleranzahl: Schlechte Idee. Abgesehen davon, dass du im Destruktor die Schüleranzahl wieder verringern solltest, sind statische Variablen an sich nicht so schön. Warum sollte ein Schüler von den anderen wissen? Nein. Wenn du Pointer verwenden würdest, würdest du so vorgehen:
void foo(Schueler* schueler, unsigned anzahl); // oder std::size_t statt unsignedMit Arrays so:
template<unsigned N> void foo(Schueler (&)schueler[N]); // Zugegeben, das ist etwas fortgeschrittenerAber optimalerweise nutzt du einfach einen Vektor:
void foo(std::vector<Schueler>& schueler); // schueler.size() verrät die Größe
-
Danke! Habe also statt dynamischen Objekten jetzt std::vector<>
Will ich jetzt starten, gehts nicht weil:LINK : fatal error LNK1104: Datei "C:\Users\Shizzophate\Documents\Visual Studio 2010\Projects\planer\Debug\planer.exe" kann nicht geöffnet werden.
========== Erstellen: 0 erfolgreich, Fehler bei 1, 0 aktuell, 0 übersprungen ==========Wieso denn jetzt der Linker?
-
Ah, das lag an meiner geistigen Behinderung. Hatte das Programm noch offen

Prima, dann bin ich ja die statischen Dinger auch los.Vielen Dank für die Hilfe nochmal an euch!