Onraku hat geschrieben:Über den Satz musste ich erstmal nachdenken.
in Pseudo-Assembler hieße das:
Code: Alles auswählen
c laden //in stack
c kopieren in ckopie
c irgendwohin zurückgeben und wieder löschen //=push oder pop? oder sagt man das nur bei einem Stack als Datenstruktur?
ckopie+1
c=ckopie und ckopie löschen // stack wie vorher
Step by Step... nehmen wir an, c wäre int, dann ist c synonym für Adresse, wo der Inhalt von c steht. c ist ein vom Stackpointer abhängiger Index. Der Wert C liegt auf dem Stack - und zwar um den Index c vom Stackpointer versetzt. Dann bedeutet ++c in Pseudoasm:
Code: Alles auswählen
Stackpointer + c_index addieren // hier ist die Adresse des Inhaltes von C
Dereferenzieren und in CPU Register laden
Inhalt CPU Register um 1 erhöhen.
Inhalt CPU Register an Rückgabeadresse schreiben
Inhalt CPU Register an dereferenzierte Adresse zurückschreiben
Während c++ bedeutet:
Code: Alles auswählen
Stackpointer + c_index addieren // hier ist die Adresse des Inhaltes von C
Dereferenzieren und in CPU Register laden
Inhalt CPU Register an Rückgabeadresse schreiben // <- vertauscht
Inhalt CPU Register um 1 erhöhen. // <- vertauscht
Inhalt CPU Register an dereferenzierte Adresse zurückschreiben
Das funktioniert mit einem Int, das passt nämlich in ein CPU-Register. Deswegen gibt es bei primitiven Datentypen auch keine Geschwindigkeitseinbußen.
Onraku hat geschrieben:Kannst du mir ein Beispiel für komplexes Objekt nennen, welches man einfach um ein erhöht?
Konstruieren wir nun einen Text, der aus 2000 Zeilen besteht und implementieren nun beide ++ Operatoren so, dass sie dem Text eine 2001. Zeile hinzufügen. Dann sieht ++text etwa so aus:
Code: Alles auswählen
Text & Text::operator ++()
{
this->Lines.append( "" );
return *this;
}
Easy. Aber text++ ist so definiert, dass das zuvor gültige Ergebnis zurück geliefert werden muss:
Code: Alles auswählen
Text Text::operator ++(int) // (!) keine Referenz als Rückgabe
{
Text that( *this ); // <- hier werden alle 2000 Zeilen kopiert und für that eine neue Liste zusammengestellt. Das ganze muss also zwischengespeichert werden
this->Lines.append( "" );
return that; // <- hier wird that nochmals an die Rückgabeadresse kopiert, also nochmal alle 2000 Zeilen kopieren, weil man ja keine Referenz zurückgeben kann!
} // hier wird that zerstört, also 2000 Zeilen wieder zerstören
Der Aufruf 'text++;' führt also zu 4000 kopierten Zeilen und wenn man das Ergebnis - den unveränderten am Ende gar nicht verwendet, ist das viel Arbeit, um nichts zu erreichen.
Zum einen erkennen Compiler solche Konstrukte heute meistens, sie konstruieren that also direkt an der Rückgabeadresse. Um hier sicherzustellen, dass man die Arbeit nicht doppelt macht, kann man sich seit C++11 die Move-Semantik benutzen. Das garantiert, dass nur 2000 Zeilen kopiert werden. Aber es muss eben ein komplett neuer Text zurückgegeben werden, also auch erzeugt werden - was bei ++text nicht der Fall ist, denn da wird einfach der veränderte Text zurückgegeben.
Man sollte C++ also tunlichst nicht verwenden, besser ist ++C.