speicherleak
-
hallo
ich bin gerade unterwegs, habe also keinen zugang zu einem richtigen debugger (auch mit einem würde ich den fehler wahrscheinlich alleine nicht finden, so gut bin ich nicht).
ich konnte schon feststellen, wo genau der fehler auftritt (in welcher codelinie).
auszug aus dem code: (die ausgabe an cout ist natürlich nur zu testzwecken so)
std::cout << "marker3" << std::endl; std::cout << "d1 = " << this->_d1 << std::endl; std::cout << "d2 = " << this->_d2 << std::endl; try { if(this->_d1 != 0) { delete[] this->_d1; } std::cout << "marker4" << std::endl; if(this->_d2 != 0) { delete[] this->_d2; } std::cout << "marker5" << std::endl; this->_d1 = _new_d1; this->_d2 = _new_d2; this->_sz_x = X; this->_sz_y = Y; this->_mode = 1; } catch(std::exception const& e) { std::cout << e.what() << std::endl;; } catch(...) { std::cout << "not specified" << std::endl;; } } std::cout << "resize done" << std::endl;ausgabe vom compiler:
resize call marker1 marker2 marker3 d1 = 0x8f25180 d2 = 0x8f25238 Runtime error time: 0 memory: 3512 signal:6da der vergleich auf ungleichheit mit 0 sicher keine probleme bereitet, ist es das delete[]. ich verstehe aber nicht ganz, wieso ein delete[] mir einen fehler verursacht obwohl das dazugehörige new[] korrekt funktioniert. ergibt für mich keinen sinn... (anhand der zeigerwerte sieht man ja, dass da von new[] eine adresse gekommen ist)
laut meiner google-suche bedeutet "signal:6" soviel wie "SIGABRT". dazu hab ich das hier gefunden:
http://en.wikipedia.org/wiki/Unix_signal schrieb:
SIGABRT
The SIGABRT signal is sent to a process to tell it to abort, i.e. to terminate. The signal is usually initiated by the process itself when it calls abort function of the C Standard Library, but it can be sent to the process from outside as well as any other signal.da ich abort nicht aufgerufen habe, weiss ich auch nicht wie das zustande kommt. von einer unbehandelten exception kann es ja nicht kommen, die habe ich eigentlich mit meinem try-catch-block abgefangen.
so viele fragen...
gruss
-
Der Fehler ist anhand des Beispiels nicht nachvollziehbar. Aber es ist ziemlich klar, was die Ursache sein wird: Manuelle Speicherverwaltung. Es gibt in C++ keinen Grund, jemals new für Arrays zu benutzen. Dafür gibt es vector. Zur allergrößten Not einen Smartpointer. Aber auf jeden Fall niemals ohne RAII-Wrapper. Ohne muss man auf zu vieles aufpassen und wirklich richtig geht es ohnehin gar nicht. Ganz sicher nicht, wenn, wie hier, Exceptions im Spiel sind. Und wer denkt,
if(this->_d1 != 0)wäre irgendwie eine sinnvolle Abfrage vor einem delete, der hat ganz sicher nicht an alles gedacht, was man dabei sonst so falsch machen könnte.
-
Bei C++ solltest du soweit es geht auf reine Zeiger verzichten. Und wenn setz den Zeiger auf 0 wenn er auf nichts mehr zeigt.
Ich vermute "this->_d1" wird doppelt freigegeben.
-
Bei C++ solltest du soweit es geht auf reine Zeiger verzichten.
Nur besitzende reine Zeiger. Als Verweis dürfen die immer noch in Gebrauch sein.
-
DarkShadow44 schrieb:
Bei C++ solltest du soweit es geht auf reine Zeiger verzichten. Und wenn setz den Zeiger auf 0 wenn er auf nichts mehr zeigt.
Ich vermute "this->_d1" wird doppelt freigegeben.Ich denke, das ist kein guter Ratschlag, mit dem Nullsetzen. Das verhindert zwar eine eventuelle doppelte Freigabe, aber der eigentliche Fehler ist, dass es überhaupt dazu kommen kann. In "richtigem" C++ programmiert man so, dass dies gar nicht möglich ist. Diese Techniken sollte er lernen. Nicht, wie man den Fehler, den er hier hat, vertuscht.
-
Ich denke, das ist kein guter Ratschlag, mit dem Nullsetzen.
Das hängt vom Kontext ab.
Natürlich nicht im Destruktor. Aber die Pauschalaussage, "setz den Zeiger auf 0 wenn er auf nichts mehr zeigt", ist doch deines Erachtens nach nicht etwa falsch. Wenn ich einen Zeiger als Member halte, dann ist es völlig selbstredend, dass 0 den ungültigen Zustand beschreibt.
-
- schrieb:
Ich denke, das ist kein guter Ratschlag, mit dem Nullsetzen.
Das hängt vom Kontext ab.
Natürlich nicht im Destruktor. Aber die Pauschalaussage, "setz den Zeiger auf 0 wenn er auf nichts mehr zeigt", ist doch deines Erachtens nach nicht etwa falsch. Wenn ich einen Zeiger als Member halte, dann ist es völlig selbstredend, dass 0 den ungültigen Zustand beschreibt.
Nicht pauschal, aber hier ist einer der Kontexte, wo es tatsächlich ganz gezielt der Fehlervertuschung dienen soll. Falls double-free das Problem ist, dann ist das Problem, dass da etwas freigegeben werden soll, was nicht freigegeben werden darf. Da ist die Lösung nicht, dass man vor der Freigabe prüft, ob man wirklich darf, sondern dass man erforscht, wieso es überhaupt zu diesem Fehler kommen konnte. Denn da ist ein Logikfehler im Code. Denn hier wird ja anscheinend angenommen, dass ein gewisses Objekt noch existiert, obwohl es vorher schon freigegeben wurde. Wo ein solcher Fehler ist, da sind andere (z.B. Zugriff auf den schon freigegebenen Bereich) nicht weit. Das muss man beheben, nicht Augen und Ohren verschließen.
(Wirklich richtig wäre natürlich, RAII zu benutzen, damit so etwas gar nicht erst vorkommen kann)
-
hm okay, kann mir vielleicht jemand sagen wie man einen vector von bools machen kann, ohne dass da die template-spezialsierung verwendet wird?
-
Was hast du denn vor?
Zur Not schreibst du dir eine eigene Klasse, die einen bool einkapselt, aber sämtliche möglichen Operationen anbietet. Das ist viel Arbeit, nicht wirklich effizient und auch fehleranfällig.
Daher: die Frage von oben...
-
eine zugriffsfunktion die eine nicht-konstante referenz auf einen bool zurückgibt (also aus dem entsprechenden vector den richtigen bool raussucht und als veränderbare referenz dem aufrufer gibt).
compilerausgabe:
main.cpp:1051:48: error: invalid initialization of non-const reference of type 'bool&' from an rvalue of type 'std::vector<bool>::reference {aka std::_Bit_reference}'edit:
wird das problem behoben und das korrekte verhalten immitiert wenn ich als rückgabewert "::std::vector<bool>::reference" statt "bool&" nehme?
-
igno schrieb:
edit:
wird das problem behoben und das korrekte verhalten immitiert wenn ich als rückgabewert "::std::vector<bool>::reference" statt "bool&" nehme?Ja, aber einfacher wäre, einfach vector char zu nehmen. Auf jeden Fall ist es keine gute Idee, selber den vector nach zu programmieren. Und wenn doch, dann auch wirklich nachprogrammieren, keine manuelle Speicherverwaltung.
-
SeppJ schrieb:
igno schrieb:
edit:
wird das problem behoben und das korrekte verhalten immitiert wenn ich als rückgabewert "::std::vector<bool>::reference" statt "bool&" nehme?Ja, aber einfacher wäre, einfach vector char zu nehmen. Auf jeden Fall ist es keine gute Idee, selber den vector nach zu programmieren. Und wenn doch, dann auch wirklich nachprogrammieren, keine manuelle Speicherverwaltung.
mein ziel ist es ja nicht wirklich einen vector nachzuprogrammieren. ich hab den quellcode ja nun überarbeitet und es wird intern in meiner klasse nun std::vector verwendet. solche getter usw brauche ich aber dennoch weil die indices nunmal nicht - wie beim vector - von 0 .. size()-1 laufen.
das problem dürfte nun behoben sein, danke für eure hilfe.
-
Falls du es noch wissen willst: Du kannst festlegen, dass das Template nicht Spezialisiert werden soll. Mit dem Makro
STD_VECTOR_BOOL_NOT_SPECIAL.