Ich habe gelesen, dass ich den Postfix-Inkrement-Operator aus Leistungsgründen vermeiden sollte (in bestimmten Fällen).
Beeinträchtigt dies jedoch nicht die Lesbarkeit des Codes? Meiner Meinung nach:
for(int i = 0; i < 42; i++);
/* i will never equal 42! */
Sieht besser aus als:
for(int i = 0; i < 42; ++i);
/* i will never equal 42! */
Aber das ist wahrscheinlich nur aus Gewohnheit. Zugegeben, ich habe nicht viele Anwendungen gesehen ++i
.
Ist die Leistung in diesem Fall so schlecht, dass die Lesbarkeit beeinträchtigt wird? Oder bin ich einfach blind und ++i
lesbarer als i++
?
c++
readability
postfix
Mateen Ulhaq
quelle
quelle
i++
bevor ich wusste, dass es die Leistung beeinträchtigen könnte++i
, also habe ich gewechselt. Zuerst sah letzteres etwas seltsam aus, aber nach einer Weile habe ich mich daran gewöhnt und jetzt fühlt es sich so natürlich an wiei++
.++i
undi++
mache verschiedene Dinge in bestimmten Kontexten, nimm nicht an, dass sie gleich sind.for (type i = 0; i != 42; ++i)
. Kann nicht nuroperator++
überladen werden, sondern auchoperator!=
undoperator<
. Präfix-Inkrement ist nicht teurer als Postfix, ungleich ist nicht teurer als kleiner als. Welche sollen wir verwenden?Antworten:
Die Fakten:
i ++ und ++ i sind gleich gut lesbar. Sie mögen keine, weil Sie nicht daran gewöhnt sind, aber es gibt im Grunde nichts, was Sie falsch interpretieren können, so dass es keine Arbeit mehr zum Lesen oder Schreiben gibt.
In einigen Fällen ist der Postfix-Operator weniger effizient.
In 99,99% der Fälle spielt es jedoch keine Rolle, weil (a) es sowieso auf einen einfachen oder primitiven Typ wirkt und es nur ein Problem ist, wenn es ein großes Objekt kopiert. (B) es wird nicht in einer Aufführung sein Kritischer Teil von Code (c) Sie wissen nicht, ob der Compiler ihn optimieren wird oder nicht.
Daher empfehle ich die Verwendung des Präfix, es sei denn, Sie benötigen speziell Postfix. Dies ist eine gute Angewohnheit, nur weil (a) es eine gute Angewohnheit ist, mit anderen Dingen präzise umzugehen, und (b) wenn Sie einmal einen blauen Mond erreicht haben, werden Sie beabsichtigen, Postfix zu verwenden und verstehe es falsch: Wenn du immer schreibst, was du meinst, ist das weniger wahrscheinlich. Es gibt immer einen Kompromiss zwischen Leistung und Optimierung.
Sie sollten Ihren gesunden Menschenverstand verwenden und nicht mikrooptimieren, bis Sie es brauchen, aber auch nicht ineffizient sein. In der Regel bedeutet dies: Schließen Sie zunächst jede Codekonstruktion aus, die selbst in nicht zeitkritischem Code inakzeptabel ineffizient ist (normalerweise ein grundlegender konzeptioneller Fehler, z. B. das Übergeben von 500 MB-Objekten als Wert ohne Grund). und zweitens wählen Sie von jeder anderen Art, den Code zu schreiben, die klarste.
Allerdings glaube ich, dass die Antwort einfach ist: Ich glaube, dass das Schreiben eines Präfixes, es sei denn, Sie benötigen speziell Postfix, (a) sehr unwahrscheinlich klarer und (b) sehr unwahrscheinlich effizienter ist, also sollten Sie das immer standardmäßig schreiben, aber Mach dir keine Sorgen, wenn du es vergisst.
Vor sechs Monaten dachte ich genauso wie Sie, dass i ++ natürlicher sei, aber es ist rein das, was Sie gewohnt sind.
BEARBEITUNG 1: Scott Meyers in "Effektiveres C ++", dem ich im Allgemeinen vertraue, sagt, dass Sie generell die Verwendung des Postfix-Operators für benutzerdefinierte Typen vermeiden sollten (da die einzige vernünftige Implementierung der Postfix-Inkrementierungsfunktion darin besteht, a zu erstellen Kopieren Sie das Objekt, rufen Sie die Funktion zum Inkrementieren des Präfix auf, um das Inkrementieren durchzuführen, und geben Sie die Kopie zurück. Kopiervorgänge können jedoch teuer sein.
Wir wissen also nicht, ob es allgemeine Regeln gibt, um (a) ob dies heute zutrifft, (b) ob dies auch (weniger) für intrinsische Typen gilt, (c) ob Sie "++" verwenden sollten etwas mehr als eine leichte Iteratorklasse überhaupt. Aber aus all den Gründen, die ich oben beschrieben habe, spielt es keine Rolle, was ich vorher gesagt habe.
EDIT 2: Dies bezieht sich auf die allgemeine Praxis. Wenn Sie denken, dass es in einem bestimmten Fall wichtig ist, sollten Sie es profilieren und sehen. Die Profilerstellung ist einfach und kostengünstig und funktioniert. Aus den ersten Prinzipien abzuleiten, was optimiert werden muss, ist schwierig und teuer und funktioniert nicht.
quelle
i++
eher daran gewöhnt sind als++i
daran, dass in dieser Frage / Antwort auf den Namen einer bestimmten populären Programmiersprache verwiesen wird ...Code immer zuerst für den Programmierer und dann für den Computer.
Wenn es einen Leistungsunterschied gibt, nachdem der Compiler Ihren Code genauestens überprüft hat, UND Sie ihn messen können UND es darauf ankommt, können Sie ihn ändern.
quelle
GCC erzeugt für beide Schleifen den gleichen Maschinencode.
C-Code
Assembly Code (mit meinen Kommentaren)
quelle
Nachdem dies nicht möglich ist, treffen wir unsere Wahl mit Bedacht :
++i
: Präfixinkrement , inkrementiert den aktuellen Wert und liefert das Ergebnisi++
: Inkrementiere Postfix , kopiere den Wert, inkrementiere den aktuellen Wert, ergebe die KopieSofern keine Kopie des alten Werts erforderlich ist, ist die Verwendung des Postfix-Inkrements eine einfache Möglichkeit, um die Dinge zu erledigen.
Ungenauigkeit entsteht durch Faulheit. Verwenden Sie immer das Konstrukt, das Ihre Absicht am direktesten zum Ausdruck bringt. Es besteht weniger Wahrscheinlichkeit, dass der zukünftige Betreuer Ihre ursprüngliche Absicht missversteht.
Auch wenn es hier (wirklich) geringfügig ist, gibt es Zeiten, in denen ich durch das Lesen von Code wirklich verwirrt war: Ich habe mich wirklich gefragt, ob die Absicht und der tatsächliche Ausdruck übereinstimmten, und natürlich haben sie (oder ich) nach ein paar Monaten erinnerte mich auch nicht ...
Es spielt also keine Rolle, ob es für Sie richtig aussieht oder nicht. Umarme KISS . In ein paar Monaten werden Sie Ihre alten Praktiken meiden.
quelle
In C ++ können Sie einen erheblichen Leistungsunterschied bewirken, wenn es sich um eine Überlastung von Operatoren handelt, insbesondere wenn Sie Vorlagencode schreiben und nicht wissen, welche Iteratoren möglicherweise übergeben werden. Das ist langsam und kann vom Compiler nicht optimiert werden.
Dies ist jedoch nicht der Fall in C, wo Sie wissen, dass es sich nur um einen trivialen Typ handelt und der Leistungsunterschied geringfügig ist und der Compiler leicht optimieren kann.
Also ein Tipp: Sie programmieren in C oder C ++ und Fragen beziehen sich auf das eine oder andere, nicht auf beide.
quelle
Die Leistung einer der beiden Operationen hängt stark von der zugrunde liegenden Architektur ab. Man muss einen gespeicherten Wert inkrementieren, was bedeutet, dass der von Neumann-Engpass in beiden Fällen der begrenzende Faktor ist.
Im Fall von ++ i müssen wir
Im Fall von i ++ müssen wir
Die Operatoren ++ und - führen ihren Ursprung auf den PDP-11-Befehlssatz zurück. Der PDP-11 könnte ein automatisches Nachinkrementieren eines Registers durchführen. Es könnte auch ein automatisches Vordekrementieren einer in einem Register enthaltenen effektiven Adresse durchführen. In beiden Fällen konnte der Compiler diese Operationen auf Maschinenebene nur dann nutzen, wenn die betreffende Variable eine "Register" -Variable war.
quelle
Wenn Sie wissen möchten, ob etwas langsam ist, testen Sie es. Nehmen Sie eine BigInteger oder ein Äquivalent, stecken Sie sie in eine ähnliche for-Schleife und verwenden Sie beide Redewendungen. Stellen Sie sicher, dass das Innere der Schleife nicht optimiert wird, und messen Sie beide.
Nachdem ich den Artikel gelesen habe, finde ich ihn aus drei Gründen nicht sehr überzeugend. Erstens sollte der Compiler in der Lage sein, die Erstellung eines Objekts zu optimieren, das niemals verwendet wird. Zweitens ist das
i++
Konzept für numerische for-Schleifen idiomatisch , sodass sich die Fälle, von denen ich sehe, dass sie tatsächlich betroffen sind, auf beschränken. Drittens liefern sie ein rein theoretisches Argument ohne Zahlen, die es stützen könnten.Vor allem aufgrund von Grund 1 gehe ich davon aus, dass sie direkt nebeneinander liegen, wenn Sie das Timing tatsächlich durchführen.
quelle
Erstens hat es keinen Einfluss auf die Lesbarkeit IMO. Es ist nicht das, woran Sie gewöhnt sind, aber es würde nur eine kurze Zeit dauern, bis Sie sich daran gewöhnt haben.
Zweitens werden Sie wahrscheinlich keinen großen Unterschied feststellen, es sei denn, Sie verwenden eine Menge Postfix-Operatoren in Ihrem Code. Das Hauptargument dafür, sie nach Möglichkeit nicht zu verwenden, ist, dass eine Kopie des Werts der ursprünglichen Variable bis zum Ende der Argumente aufbewahrt werden muss, in denen die ursprüngliche Variable noch verwendet werden kann. Das sind je nach Architektur entweder 32 oder 64 Bit. Das entspricht 4 oder 8 Bytes oder 0,00390625 oder 0,0078125 MB. Es ist sehr wahrscheinlich, dass Sie bei den heutigen Computerressourcen und der Geschwindigkeit nicht einmal einen Unterschied bemerken, wenn Sie nicht eine Tonne von ihnen verwenden, die für einen sehr langen Zeitraum gespeichert werden müssen, um von Postfix zu Präfix zu wechseln.
BEARBEITEN: Vergessen Sie diesen verbleibenden Teil, da meine Schlussfolgerung als falsch erwiesen wurde (abgesehen davon, dass ++ i und i ++ nicht immer dasselbe tun ... das ist immer noch wahr).
Vorhin wurde auch darauf hingewiesen, dass sie in einigen Fällen nicht dasselbe tun. Seien Sie vorsichtig beim Umschalten, wenn Sie dies wünschen. Ich habe es noch nie ausprobiert (ich habe immer Postfix verwendet), daher weiß ich es nicht genau, aber ich denke, der Wechsel von Postfix zu Präfix führt zu unterschiedlichen Ergebnissen: (Auch hier kann ich mich irren ... hängt vom Compiler ab / Dolmetscher auch)
quelle
Ich denke semantisch,
++i
macht mehr Sinn alsi++
, also würde ich mich an die erste halten, außer es ist üblich, dies nicht zu tun (wie in Java, wo Sie es verwenden sollten,i++
weil es weit verbreitet ist).quelle
Es geht nicht nur um Leistung.
Manchmal möchten Sie das Kopieren gar nicht erst implementieren, weil es keinen Sinn ergibt. Und da die Verwendung des Präfixinkrements nicht davon abhängt, ist es einfach, sich an das Präfixformular zu halten.
Und verschiedene Inkremente für primitive und komplexe Typen zu verwenden, ist wirklich unlesbar.
quelle
Wenn du es nicht wirklich brauchst, bleibe ich bei ++ i. In den meisten Fällen ist dies beabsichtigt. Es ist nicht sehr häufig, dass Sie i ++ benötigen, und Sie müssen immer zweimal überlegen, wenn Sie ein solches Konstrukt lesen. Mit ++ i ist es ganz einfach: Sie fügen 1 hinzu, verwenden es und dann ist es immer noch dasselbe.
Also, ich stimme voll und ganz @martin beckett zu: Mach es dir leichter, es ist schon schwer genug.
quelle