Unberechenbare Programmabstürze - Compiler Schuld?
-
quaid schrieb:
Es ist klar, das sowas immer fehleranfällig ist, aber wie erwähnt, funktioniert es meistens nach dem Programmstart
Das bedeutet, es funktioniert eben nicht. Undefiniertes Verhalten kann leicht entstehen, wenn man viel mit rohen Zeigern hantiert.
quaid schrieb:
Kann denn sowas am Compiler liegen? [...]
Die Frage ist letztendlich die: Muss ich immer annehmen, dass ich als Entwickler den Fehler produziere? Oder wirkt ein Compilerwechsel manchmal Wunder?
Normalerweise kannst du davon ausgehen, dass du schuld bist, besonders bei modernen Compilern. Zum Testen kannst du aber schon einmal einen anderen Compiler probieren, doch sei gewarnt: Wenn es dort nicht abstürzt, heisst das nicht, dass das Programm keine Fehler mehr hat, geschweige denn, dass der andere Compiler verbuggt ist. Also bringt dir das schlussendlich nicht allzu viel, um Fehler zu finden.
quaid schrieb:
gesagt, es wird viel mit Pointern rumhantiert. Da kommen schon ein paar Tausend Verkettungen vor, die dann stückweise auch wieder gelöscht werden, also ein wahres Pointer Gemetzel.
Warum machst du sowas überhaupt? Gerade C++ bietet sehr viele schöne Möglichkeiten, Zeiger zu kapseln und die Handhabung sicher zu gestalten. Wenn du diese nicht nutzt, musst du dich nicht über Fehleranfälligkeit wundern...
-
quaid schrieb:
Die Frage ist letztendlich die: Muss ich immer annehmen, dass ich als Entwickler den Fehler produziere?
Grundsätzlich erstmal ja. Solange du nur Annahmen machst, mach die Annahme dass der Fehler bei dir liegt. Dass der Compiler n Fehler gemacht hat solltest du erst dann "annehmen" wenn du es beim Debugging bewiesen hast.
-
Wow, hier kriegt man aber schnell Antworten, dankeschön!

Ich kenn mich in C++ nicht so aus, welche Alternativen zu Pointern gibt es denn? Es sollte halt schnell gehen, weil wir Datensätze von mehreren 100MB einlesen die dann in einer komplexen Datenstruktur organisiert werden.
Ich kenne halt nur den Grundsatz, dass auf ein
delete myPointerimmer ein
myPointer = NULLfolgen sollte, und dass man in verketteten Listen das "next" Element auch mit NULL initialisiert. Ausserdem, dass man IMMER auf (!(myPointer == NULL)) checken soll, bevor man irgendwas macht.
Aber das habe ich überall gemacht

Ich werd jetzt aber nochmal suchen...
-
quaid schrieb:
Ich kenn mich in C++ nicht so aus, welche Alternativen zu Pointern gibt es denn? Es sollte halt schnell gehen, weil wir Datensätze von mehreren 100MB einlesen die dann in einer komplexen Datenstruktur organisiert werden.
Sicherheit sollte generell vor Geschwindigkeit gehen. Im Übrigen bleibt abzuwarten, ob die Alternativen merklich langsamer sind.
Ganz zentral und wichtig sind in C++ die STL-Container. Da gibt es eine Vielzahl fertiger Datenstrukturen, die effizient programmiert sind und dir die Speicherverwaltung und das Rumgefrickel abnehmen. Darunter hat es auch eine verkettete Liste (
std::list). Ich empfehle dir wirklich unbedingt, diese Containerklassen zu verwenden. Durch Assertions im Debug-Modus werden zum Beispiel bereits sehr viele Fehler aufgedeckt.
-
Ich weiß nicht genau, ob Nexus das schon meinte, aber:
Es hört sich nicht so an, als ob du wirklich so viele pointer brauchen würdest...
Datensätze einlesen geht auch ohne Pointer...
In Listen/... stopfen geht (zumindest an der Schnittstelle) auch ohne Pointer...bb
edit:
btw:
(!(myPointer == NULL))->(myPointer != NULL)->(myPointer)
-
quaid schrieb:
...Ich arbeite sehr viel mit Pointern und std::vector<bla>....
Hi,
ich wollte nur einmal in Erinnerung rufen, dass Iteratoren (und damit auch Zeiger) auf Vektorelemente ungültig werden, wenn man den vector verändert (vergrößert/verkleinert/kopiert/Elemente entfernt/....).
Das ist ein ziemlich komplexes Problem bei Containern und wird gerne mal übersehen.Gruß,
Simon2.
-
Simon2 schrieb:
Das ist ein ziemlich komplexes Problem bei Containern und wird gerne mal übersehen...
...und bei einer gut implementierten Standardbibliothek in vielen Fällen durch Assertions aufgedeckt.

Ich hab das Gefühl, das Problem liegt hier eher bei den Zeigern. Nur so eine Vermutung...
-
quaid schrieb:
Ich kenne halt nur den Grundsatz, dass auf ein
delete myPointerimmer ein
myPointer = NULLfolgen sollte, und dass man in verketteten Listen das "next" Element auch mit NULL initialisiert. Ausserdem, dass man IMMER auf (!(myPointer == NULL)) checken soll, bevor man irgendwas macht.
Wenn solche Krücken für dich "Grundsätze" sind, dann geh davon aus, dass das Problem mit Sicherheit in deinem Code liegt. Bei einem ordentlichen Design braucht man so etwas eigentlich nicht.
-
Super, danke für eure Antworten! Jetzt hab ich auf jeden Fall erstmal genug zu tun, bevor sich (hoffentlich keine) neuen Fragen ergeben.
Ich werd mir die STL für die Zukunft merken. Immerhin verwende ich ja bereits zum Teil std::vector<...> aber mir war nicht bewusst, dass es da ein ganzes Paket für jedes Einsatzgebiet gibt.
Da ich aber schon mittendrin bin, im Pointer-Dschungel habe ich jetzt auch den Ehrgeiz das Ding zum Laufen zu kriegen. Werd mir mal anschauen ob ich irgendwo in einen Vektor reinzeige, das war ein guter Einwand.
Nochmal vielen Dank, tolles Forum hier!

-
MFK schrieb:
quaid schrieb:
Ich kenne halt nur den Grundsatz, dass auf ein
delete myPointerimmer ein
myPointer = NULLfolgen sollte, und dass man in verketteten Listen das "next" Element auch mit NULL initialisiert. Ausserdem, dass man IMMER auf (!(myPointer == NULL)) checken soll, bevor man irgendwas macht.
Wenn solche Krücken für dich "Grundsätze" sind, dann geh davon aus, dass das Problem mit Sicherheit in deinem Code liegt. Bei einem ordentlichen Design braucht man so etwas eigentlich nicht.
Und wenn man alles richtig macht, braucht man auch kein Forum

-
quaid schrieb:
Erfolgsquote liegt bei gefühlten 79%
Was denn, keine Kommastellen? Hätte mir mehr von dir erwartet...
-
Nexus schrieb:
Simon2 schrieb:
Das ist ein ziemlich komplexes Problem bei Containern und wird gerne mal übersehen...
...und bei einer gut implementierten Standardbibliothek in vielen Fällen durch Assertions aufgedeckt.

Ich hab das Gefühl, das Problem liegt hier eher bei den Zeigern. Nur so eine Vermutung...
Meine doch auch!
Ungültig gewordene Iteratoren könnte eine STL (vermutlich aber auch nur im Debugmodus) evtl. noch abfangen ... bei Zeigern fällt mir nicht ein, wie das gehen könnte.
Meine Argumentation war eher: Wenn schon Iteratoren ungültig werden, dann Zeiger erst recht.Gruß,
Simon2.
-
So, ich habe mich jetzt vom Pointer Wirr-Warr verabschiedet und arbeite mit den STL-Containern. Alles läuft super und der Code sieht auch gleich viiieeeeel sauberer aus. Schnell genug arbeiten die Dinger auch. Die paar hundert MB werden jedenfalls in 20 Sekunden abgearbeitet und währenddessen werden Millionen(!) von vectoren und listen erzeugt, verändert und gelöscht.
Ich hänge jetzt an einer anderen Stelle. Wenn einer Lust hat, kann er mir schnell sagen wie ich assertions von vectoren abfangen kann, denn das brauch ich grad.
Ansonsten vielen vielen Dank für alle Antworten und den Tip mit der STL. Ich bin definitiv bekehrt worden.

Also. Thema geschlossen.
Tschöö!
-
assert fängt man nicht ab. die gibts, wenn du was programmiert hast was nicht sein soll und das muss geändert werden.
-
Hi quaid,
uknow schrieb:
assert fängt man nicht ab. die gibts, wenn du was programmiert hast was nicht sein soll und das muss geändert werden.
Sehe ich auch so .... allerdings vermute ich, dass Du eine assertion von vector::operator[]() (im Debugmode) wegen Indexüberschreitung bekommst.
Als Erstes solltest Du da debuggen, ob/wo/warum Du dem vector irgendwohin greifen willst, wo er es nicht gerne hat ;).
Dann solltest Du entscheiden, ob
a) ein simpler Programmierfehler vorliegt,
b) Du mit einer vorherigen Abfrage klarkommst oder
c) Du besser vector::at() verwendest (der prüft solche Fehler).c) würde ich nicht unbedingt als Standardlösung vorschlagen, aber es gibt Programme, da ist es das richtige Mittel (wenn man permanent Indizes von "außen" hereingereicht bekommt und jedesmal selbst prüfen müsste, kann man das besser at() machen lassen).
Gruß,
Simon2
-
Ich hab den Fehler gefunden, und diesmal lags nicht an mir!

Bei sehr großen Datensätzen kam der Rechner nicht mehr mit. Genauer gesagt, nachdem der 5.450.153te Vector angelegt wurde. Diese Vektoren habe ich nun durch statische Arrays ersetzt, da ohnehin nicht mehr als 3 Einträge gebraucht werden. Jetzt funktioniert alles bestens.
Man sollte also doch nicht unbedingt immer grundsätzlich mit Vektoren arbeiten :p
So, nochmal vielen Dank für alle Antworten und tschöö!
-
quaid schrieb:
Bei sehr großen Datensätzen kam der Rechner nicht mehr mit. Genauer gesagt, nachdem der 5.450.153te Vector angelegt wurde. Diese Vektoren habe ich nun durch statische Arrays ersetzt, da ohnehin nicht mehr als 3 Einträge gebraucht werden. Jetzt funktioniert alles bestens.
Schön, wenn es funktioniert - auch, wenn mir der Grund ein wenig unglaubwürdig erscheint x)
bb
-
quaid schrieb:
Bei sehr großen Datensätzen kam der Rechner nicht mehr mit. Genauer gesagt, nachdem der 5.450.153te Vector angelegt wurde. Diese Vektoren habe ich nun durch statische Arrays ersetzt, da ohnehin nicht mehr als 3 Einträge gebraucht werden. Jetzt funktioniert alles bestens.
Darf ich fragen, wofür du 5'450'153 mal einen
std::vectorbrauchst?quaid schrieb:
Man sollte also doch nicht unbedingt immer grundsätzlich mit Vektoren arbeiten :p
Das stimmt durchaus, aber mich würde ehrlich gesagt interessieren, ob es hier wirklich auch der Fall ist, bzw. ob man vielleicht nicht einiges mehr anders machen könnte.
Aber das ist natürlich dir überlassen, ob du uns noch weiterhin in dem Bereich konsultieren möchtest

Grüssli
-
Da ich ja jetzt überaus stolz bin, dass alles funktioniert erkläre ichs natürlich auch gerne.

Ich lese einen 3D-Datensatz ein und speichere den in einer Face-Based Datenstruktur. Ich habe also alle Dreiecke inklusive Nachbarschaftsbeziehung im Speicher. Die Dreiecke werden alle in einen Vektor gepackt. Theoretisch kann jedes Dreieck beliebig viele Nachbarn haben (Nachbarschaft ist über die Kanten definiert). Diese Nachbarliste wollte ich halt auch bequem in einem Vektor speichern.
Allerdings haben wir wie gesagt riesige Datensätze mit mehreren Millionen Dreiecken, womit auch Millionen von Vektoren angelegt wurden. Bei besagter Zahl war eben Schluss. Genauer gesagt war nicht beim Anlegen eines Nachbarvektors Schluss, sondern bei einem ...push_back(newNeighborId).
Ich hab die Vektoren entfernt und einen statischen Array für jedes Dreieck angelegt. Da die Netze mit denen wir arbeiten immer Manifolds sind, also über jede Kante nur maximal einen Nachbarn haben, ist das so okay.
Wenn ich aber irgendwann mal non-manifolds einlesen will ist das natürlich doof, aber wer weiß ob das überhaupt passiert!So, ich hoffe das hilft euch jetzt beim Einschlafen

-
quaid schrieb:
...einen 3D-Datensatz ...
Also da wundere ich mich sowieso, wie Du auf vector gekommen bist. Das klingt sogar so als ob Du mit einem struct auch gut gefahren wärst.
vector ist großartig, wo man eine variable oder eine große Dimension hat und die Elemente gleichwertig sind.
Das scheint in Deinem Fall nicht zuzutreffen.
Ich bin nicht einmal davon überzeugt, dass ein Array für Dich die beste Wahl ist.
Vermutlich hast Du doch noch "Fachlichkeit in der Dimension versteckt", oder?
(so in dem Sinne "a[0] ist der x-Wert, a[1] ist der y-Wert und a[2] ist der z-Wert")Gruß,
Simon2.