Ich habe Stroustrups "The C ++ Programming Language" gelesen, in der er sagt, dass es zwei Möglichkeiten gibt, einer Variablen etwas hinzuzufügen
x = x + a;
und
x += a;
Er bevorzugt, +=
weil es höchstwahrscheinlich besser umgesetzt wird. Ich denke, er meint, dass es auch schneller funktioniert.
Aber ist es wirklich so? Wie überprüfe ich, ob es vom Compiler und anderen Dingen abhängt?
c++
performance
operators
Chiffa
quelle
quelle
Antworten:
Jeder Compiler wert sein Salz wird erzeugen genau die gleiche Maschinensprachsequenz für beiden Konstrukte für jeden eingebauten Typen (
int
,float
usw.), solange die Aussage wirklich so einfach , wiex = x + a;
und Optimierung aktiviert ist . (Insbesondere GCCs-O0
, der Standardmodus, führen Anti-Optimierungen durch , z. B. das Einfügen völlig unnötiger Speicher in den Speicher, um sicherzustellen, dass Debugger immer variable Werte finden können.)Wenn die Aussage jedoch komplizierter ist, können sie unterschiedlich sein. Angenommen, es
f
handelt sich um eine Funktion, die dann einen Zeiger zurückgibtruft
f
nur einmal an, währendruft es zweimal auf. Wenn
f
Nebenwirkungen auftreten, ist einer der beiden falsch (wahrscheinlich der letztere). Selbst wennf
keine Nebenwirkungen auftreten, kann der Compiler den zweiten Aufruf möglicherweise nicht eliminieren, sodass letzterer möglicherweise langsamer ist.Und da es sich hier um C ++ handelt, ist die Situation für Klassentypen, die
operator+
und überladen, völlig andersoperator+=
. Wennx
es sich um einen solchen Typ handelt, wird vor der Optimierung inx += a
übersetztwährend
x = x + a
übersetzt zuWenn die Klasse ordnungsgemäß geschrieben ist und der Optimierer des Compilers gut genug ist, werden beide dieselbe Maschinensprache generieren, aber es ist nicht sicher, wie es für integrierte Typen ist. Dies ist wahrscheinlich das, woran Stroustrup denkt, wenn er zur Verwendung ermutigt
+=
.quelle
expr
zuvar
isvar+=expr
und zum Schreiben in die andere Richtung verwirrt die Leser.*f() = *f() + a;
, möchten Sie vielleicht einen genauen Blick darauf werfen, was Sie wirklich erreichen wollen ...1
ist eine Konstante,a
kann ein flüchtiger, ein benutzerdefinierter Typ oder was auch immer sein. Völlig anders. Tatsächlich verstehe ich nicht, wie dies überhaupt geschlossen wurde.Sie können dies überprüfen, indem Sie sich die Demontage ansehen, die gleich sein wird.
Bei Basistypen sind beide gleich schnell.
Dies wird durch einen Debug-Build generiert (dh keine Optimierungen):
Für benutzerdefinierte Typen , wo Sie überlasten
operator +
undoperator +=
hängt es von ihren jeweiligen Implementierungen.quelle
a
1 undx
istvolatile
der Compiler generieren könnteinc DWORD PTR [x]
. Das ist langsam.operator +
, um nichts zu tun undoperator +=
die 100000. Primzahl zu berechnen und dann zurückzukehren. Das wäre natürlich eine dumme Sache, aber es ist möglich.++x
und sinnvoll ist,temp = x + 1; x = temp;
sollte es höchstwahrscheinlich in Assembly anstatt in C ++ geschrieben werden ...Ja! Es ist schneller zu schreiben, schneller zu lesen und schneller herauszufinden, für letztere in dem Fall, der
x
Nebenwirkungen haben könnte. Für die Menschen ist es also insgesamt schneller. Die menschliche Zeit kostet im Allgemeinen viel mehr als die Computerzeit, also müssen Sie danach gefragt haben. Richtig?quelle
Es hängt wirklich von der Art von x und a und der Implementierung von + ab. Zum
Der Compiler muss ein temporäres T erstellen, um den Wert von x + a zu enthalten, während er ihn auswertet, das er dann x zuweisen kann. (Während dieses Vorgangs kann x oder a nicht als Arbeitsbereich verwendet werden.)
Für x + = a benötigt es keine temporäre.
Bei trivialen Typen gibt es keinen Unterschied.
quelle
Der Unterschied zwischen
x = x + a
undx += a
ist der Arbeitsaufwand, den die Maschine durchmachen muss - einige Compiler optimieren ihn möglicherweise (und tun dies normalerweise), aber wenn wir die Optimierung für eine Weile ignorieren, geschieht dies normalerweise im vorherigen Code-Snippet, dem Die Maschine muss den Wertx
zweimal nachschlagen , während in letzterem Fall diese Suche nur einmal erfolgen muss.Wie bereits erwähnt, sind die meisten Compiler heute jedoch intelligent genug, um die Anweisungen zu analysieren und die daraus resultierenden erforderlichen Maschinenanweisungen zu reduzieren.
PS: Erste Antwort zum Stapelüberlauf!
quelle
Da Sie dieses C ++ beschriftet haben, können Sie anhand der beiden von Ihnen veröffentlichten Anweisungen nichts erkennen. Sie müssen wissen, was 'x' ist (es ist ein bisschen wie die Antwort '42'). Wenn
x
es sich um einen POD handelt, wird es keinen großen Unterschied machen. Wennx
es sich jedoch um eine Klasse handelt, kann es zu Überladungen für die Methodenoperator +
und kommenoperator +=
, die unterschiedliche Verhaltensweisen aufweisen können, die zu sehr unterschiedlichen Ausführungszeiten führen.quelle
Wenn Sie sagen,
+=
Sie machen dem Compiler das Leben viel einfacher. Damit der Compiler erkennt, dass diesx = x+a
dasselbe ist wiex += a
, muss der CompilerAnalysieren Sie die linke Seite (
x
), um sicherzustellen, dass sie keine Nebenwirkungen hat und sich immer auf denselben l-Wert bezieht. Zum Beispiel könnte es seinz[i]
, und es muss sicherstellen, dass beidez
undi
nicht ändern.Analysieren Sie die rechte Seite (
x+a
) und stellen Sie sicher, dass es sich um eine Summierung handelt und dass die linke Seite einmal und nur einmal auf der rechten Seite vorkommt, obwohl sie wie in transformiert werden könntez[i] = a + *(z+2*0+i)
.Wenn das, was meinen Sie ist hinzuzufügen ,
a
zux
dem Compiler Schriftsteller schätzt es , wenn Sie nur sagen , was Sie meinen. Auf diese Weise sind Sie nicht der Teil des Compilers ausübt , dass seine Verfasser hofft er / sie bekam alle Fehler aus, und das nicht tatsächlich Leben einfacher für Sie, wenn Sie ehrlich nicht den Kopf bekommen kann aus des Fortran-Modus.quelle
Stellen Sie sich als konkretes Beispiel einen einfachen komplexen Zahlentyp vor:
Für den Fall a = a + b muss eine zusätzliche temporäre Variable erstellt und anschließend kopiert werden.
quelle
Sie stellen die falsche Frage.
Es ist unwahrscheinlich, dass dies die Leistung einer App oder Funktion beeinträchtigt. Selbst wenn dies der Fall wäre, müssen Sie den Code profilieren und wissen, wie er Sie mit Sicherheit beeinflusst. Anstatt sich auf dieser Ebene Sorgen zu machen, welche schneller ist, ist es viel wichtiger , in Bezug auf Klarheit, Korrektheit und Lesbarkeit zu denken.
Dies gilt insbesondere dann, wenn Sie bedenken, dass sich Compiler im Laufe der Zeit weiterentwickeln, auch wenn dies ein wesentlicher Leistungsfaktor ist. Jemand könnte eine neue Optimierung finden und die richtige Antwort heute kann morgen falsch werden. Es ist ein klassischer Fall vorzeitiger Optimierung.
Das soll nicht heißen, dass Leistung überhaupt keine Rolle spielt ... Nur dass es der falsche Ansatz ist, um Ihre Perfektionsziele zu erreichen. Der richtige Ansatz besteht darin, mithilfe von Profiling-Tools zu ermitteln, wo Ihr Code tatsächlich seine Zeit verbringt und wo Sie sich auf Ihre Bemühungen konzentrieren können.
quelle
Ich denke, das sollte von der Maschine und ihrer Architektur abhängen. Wenn seine Architektur eine indirekte Speicheradressierung zulässt, KANN der Compiler-Writer stattdessen einfach diesen Code verwenden (zur Optimierung):
Wobei übersetzt werden
i = i + y
könnte (ohne Optimierung):i
Allerdings sollten auch andere Komplikationen in Betracht gezogen werden, z. B. ob es sich um eine Funktion handelt, die einen Zeiger zurückgibt usw. Die meisten Compiler auf Produktionsebene, einschließlich GCC, erzeugen für beide Anweisungen denselben Code (wenn sie Ganzzahlen sind).quelle
Nein, beide Wege werden gleich behandelt.
quelle