Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?
-
@JTR666 sagte in Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?:
@SeppJ Also nochmal bei 0 anfangen?
Na, bevor du weiter Quatsch lernst. Je mehr Quatsch du lernst, desto schwieriger wird es, diesen zu vergessen. Besonders weit bist du ja noch nicht, insofern ist jetzt ja noch ein guter Zeitpunkt zu wechseln.
Falls du das anders siehst, stell' dir mal vor, du würdest ein Instrument oder einen Sport anhand von Internetvideos lernen und gingest jetzt zu einem professionellen Lehrer/Trainer. Und der sagt dir, dass du dir eine falsche Haltung angewöhnt hast, weil dich bisher niemand korrigiert hat. Würdest du darauf bestehen, so weiter zu machen, wie bisher? Wohl hoffentlich nicht, auch dann nicht, wenn dir die neue Haltung vom Trainer zuerst schwer fällt, und du damit anfangs Sachen nicht schaffst, die du mit deiner falschen Haltung schon konntest.
-
@JTR666 sagte in Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?:
@Quiche-Lorraine Was hat er gemacht?
Er hat eine Speicherverwaltung für einen Uralt-Controller geschrieben. Dazu hat er einen Großteil des RAMs (32 kByte) für sich beansprucht und eigene HeapNew() und HeapDelete() Funktionen geschrieben. Und da er die Speicherverwaltung sich selbst organisierend machte um Fragmentierung zu vermeiden, lieferten HeapNew() und HeapDelete() nur IDs zurück. Eine Funktion HeapPtr() lieferte zu einer ID den Pointer zurück.
Und dann wollte eine Funktion beispielsweise eine Liste kopieren und machte folgendes:
// Bestimmte Pointer auf zu kopierendes Array tMyArray* Array = HeapPtr(ArrayID); // Lege neues Array an int NewArrayID = HeapNew(sizeof(tMyArray)); tMyArray* NewArray = HeapPtr(NewArrayID); // Kopiere Elemente for (i = 0; i < Array->Count; i++) { NewID = HeapNew(4); memcpy(GetPtr(NewID), GetPtr(Array->Data[i]), 4); NewArray->Data[i] = NewID; NewArary->Count++; }
Den Fehler sieht man auf den ersten Blick nicht. Aber das HeapNew() organisierte manchmal den Speicher um s.d. alle Zeiger auf dem Speicherbereich ungültig wurden und auf potenziell ungültige Daten zeigten.
Und das dumme daran, es stürzte noch nicht einmal ab. Der Zeiger konnte nach einer HeapNew() auf einmal auf einen Speicherbereich zeigen welcher von anderen Funktionen benutzt wurden. Und dann kopierte die Funktion halt Daten nach irgentwo.
Das ganze funktionierte in 99% der Fälle aber in 1% der Fälle verursachte es schwer nachvollziehbare Datenverluste.
Und dann portierte er das ganze auf Windows.
Als ich die Speicherreservierung auf std::vector umstellte, stürzte mir das Programm erst einmal ab. Und das war auch gut so. Denn nur so fand ich den Fehler.
PS:
Aber auch so etwas habe ich schon gesehen:#include <stdio.h> #include <vector> int main () { std::vector<int> L{1}; int* L1 = &L[0]; for (int i = 0; i < 20; i++) { printf("%i ", *L1); L.push_back(i); } return 0;
}
-
@JTR666
Die Lehre aus dieser Geschichte: Pointer sind kleine gemeine Biester, welche einem das Programmierleben orgentlich versauen können. Aber machmal sind sie auch sehr hilfreiche Wesen.
-
@SeppJ Also kennst du das für Dummies-Buch, oder wie?
-
@Quiche-Lorraine Eine grammatikalische Frage:
Meinst du in der ersten Kommentar-Zeile mit "Bestimmte", dass deine Bekannter die Zeiger bestimmte, oder dass es sich um bestimmte, also spezielle, Zeiger handelt?
-
@Quiche-Lorraine Also beim zweiten Quellcode (dem ich zugegebenermaßen besser weit besser folgen kann als dem ersten), kommt es mir so vor, als versuche er/sie immer wieder einen Vektor mit nur einem Wert (warum dann überhaupt einen Vektor aufspannen?) zu überschreiben.
Und beim ersten meinst du dann sicherlich, dass sich das Programm einfach Speicher nimmt, der schon von externen Programmen belegt (aber wohl nicht ordentlich reserviert) war, und diesen dann einfach überschreibt, richtig?
-
@SeppJ Btw:
Das Buch ist das was ich meinte, dass ich von Stroustrup hab:
https://books.google.de/books/about/Die_C++_Programmiersprache.html?id=YEy9BgAAQBAJ&printsec=frontcover&source=kp_read_button&redir_esc=y#v=onepage&q&f=false
-
@JTR666 sagte in Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?:
@Quiche-Lorraine Also beim zweiten Quellcode (dem ich zugegebenermaßen besser weit besser folgen kann als dem ersten), kommt es mir so vor, als versuche er/sie immer wieder einen Vektor mit nur einem Wert (warum dann überhaupt einen Vektor aufspannen?) zu überschreiben.
Mag sein, dass es dir so vorkommt, ist aber nicht so. Schau genauer hin.
Und beim ersten meinst du dann sicherlich, dass sich das Programm einfach Speicher nimmt, der schon von externen Programmen belegt (aber wohl nicht ordentlich reserviert) war, und diesen dann einfach überschreibt, richtig?
Nein. Du kannst bei modernen Betriebssystemen nicht einfach so in Speicher anderer Programme schreiben. Das
Array
aus Zeile 2 darf nach demHeapNew
-Aufruf in Zeile 4 schlicht nicht mehr verwendet werden.
-
@Quiche-Lorraine Dann vermute ich mal, dass der Pointer, der ja auf das erste (und einzige) Element des Vektors zeigt, immer an die Adresse auf die er zeigt ein neues Element schiebt, und dadurch die vorherigen Elemente irgendwo hingeschoben, aber nicht gelöscht werden?
-
@JTR666 sagte in Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?:
@Quiche-Lorraine Dann vermute ich mal, dass der Pointer, der ja auf das erste (und einzige) Element des Vektors zeigt, immer an die Adresse auf die er zeigt ein neues Element schiebt, und dadurch die vorherigen Elemente irgendwo hingeschoben, aber nicht gelöscht werden?
Wie kommst du auf deine Vermutung? Schau dir das doch mal Zeile für Zeile an. Wie soll ein Pointer irgendwas schieben?
-
@Schlangenmensch Nicht der Pointer. Sondern push_back schiebt ja.
Denn ich denke mal, dass die Vektorgröße nicht dynamisch ist und somit immer nur aus einem Element besteht.
-
@JTR666 sagte in Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?:
Denn ich denke mal, dass die Vektorgröße nicht dynamisch ist und somit immer nur aus einem Element besteht.
Und was bringt dich auf die Idee? Um das zu verkürzen: Das ist falsch. Genau das ist die Anwendung von std::vector: als dynamisches array.
push_back()
fügt ein Element ans Ende ein und vergößert es damit.
-
Dieser Beitrag wurde gelöscht!
-
@JTR666 Probier es doch mal aus. Das ist auch nicht das Problem.
%i
ist nur ein format specifier, damit printf weiß, was es auszugeben hat.Edit: Arbeite mal das Buch von Bjarne Stroustrup durch
-
@Schlangenmensch Im Buch steht im Vorwort, dass es nicht für Anfänger sei (im von ihm selbst geschriebenen Vorwort :-/)
Okay, interessant. Der gibt dann immer wieder die Adresse von L[0] in den Speicher ein.
Aber die Frgae ist nur: Wieso? Denn dereferenziert ist der Pointer ja in printf()
Der Pointer *L weißt ja immer auf die selbe Adresse, nämlich die vom ersten Vektor-Wert.
Diese bekommt ja auch push_back(), und schiebt. Oder kann es sein, dass push_back() den neuesten Wert nicht zwingend auf die Adresse schiebt, auf welche *L1 zeigt?
Denn bei der Ausgabe hast du 1 1 0 1 und dann immer ne recht große Dezimalzahl (weswegen ich vermute, dass das keine Adresse ist, sondern ein Wert der dann auf dieser Adresse liegt.)
-
Der Vektor wird veränder durch das push_back, wer garantiert dir das
, nämlich die vom ersten Vektor-Wert.
Manchmal hilft ein Blick in die Doku.
http://www.cplusplus.com/reference/vector/vector/push_back/
-
@Schlangenmensch Das war nur meine Vermutung^^
Okay, erklärs mir mal!Denn mich haben halt diese Werte irritiert.
Zuerst 1, dann 0, dann wieder 1 und noch eine 1 und dann immer eine (bei jeder Ausführung andere) große Zahl...
-
Ich habe eigentlich alles geschrieben, was nötig ist um sich das zusammen zu suchen
Aber ich will mal nicht so sein, ist ja schließlich fast Wochenende.
Wenn ein
std::vector
erstellt wird, reserviert der eine bestimmte Menge an Speicher in die eine bestimmte Menge an Elementen passt, dass ist seine Kapazität. Er kann so viele Elemente aufnehmen bis die Größe des Vektors die Kapazität ausschöpft. Wenn mehr Elemente aufgenommen werden müssen, muss er mehr Speicher anfordern. Jetzt kann man aber nicht sagen, "Ok, nehmen wir mehr Speicher an der Stelle 'letztes Element + 1'" weil da könnte ja sonst was sein, sondern der Vektor reserviert einen neuen größeren Speicherbereich und kopiert die Elemente die bereits enthalten sind, in den neuen Bereich um und gibt den alten Speicherbereich wieder frei.In dem Moment, in dem der Pointer angelegt wird, zeigt er auf das erste Element im Vektor. Wenn der jetzt aber mehr Speicher braucht und sich neuen reserviert, wird der alte Speicherbereich freigegeben. Und voilá, der Pointer zeigt nach irgendwo, aber nicht mehr auf eine Stelle im Speicher, die du unter Kontrolle hast.
-
@Schlangenmensch Aaaahhh! Okay, das macht Sinn^^
Deswegen sollte man auch die Finger von dynamischen Arrays lassen, oder? (Hab ich zumindest mal gelesen)
Ist das richtig, wenn ich sag, dass ein int-Vektor, wenn man ihm die Größe {1} gibt, er 4 Byte groß ist? Denn zumindest ist bei Code::Blocks erst mal jeder int-Wert diese Größe...
-
@JTR666 Finger von selbstprogrammierten dynamische Arrays lassen.
std::vector
ist toll@JTR666 sagte in Kann mir jemand eben erklären, wie die Kopierkonstruktoren mit Referenzparameter funktionieren?:
Ist das richtig, wenn ich sag, dass ein int-Vektor, wenn man ihm die Größe {1} gibt, er 4 Byte groß ist? Denn zumindest ist bei Code::Blocks erst mal jeder int-Wert diese Größe...
Nö, ist es nicht ;). Zum einen kannst du nicht davon ausgehen, das int 4 Byte groß ist. Auch wenn das wahrscheinlich auf die meisten Systeme zutrifft, wird es meines Wissens nach nirgends garantiert.
Zum anderen: Wenn wir annehmen, dass ein int 4 Byte groß ist, hat ein Vektor von ints, dem du die Größe 1 mitgibst, 4 zusammenhängende Bytes an Speicher reserviert.
Die Frage ist, was du mit "größe" meinst. Der Vektor meint mit "size()" die Anzahl an Elemente. Der Vektor selbst, besteht aus mehr, als dem reinen dynamischen Array. Zumindest muss der sich merken, wie viel Speicher er reserviert hat.