Incrementeren in C++ – wanneer u x ++ of ++ x wilt gebruiken?

Ik ben momenteel C++ aan het leren en ik heb een tijdje geleden over de incrementatie geleerd.
Ik weet dat je “++ x” kunt gebruiken om de incementatie eerder en “x ++” te maken om het na te doen.

Toch weet ik het echt niet wanneer je een van de twee moet gebruiken … ik heb nooit echt “++ x” gebruikt en dat dingen altijd goed werkten tot nu toe – dus, wanneer zou ik het moeten gebruiken?

Voorbeeld: in een voor lus, wanneer is het de voorkeur om “++ x” te gebruiken?

Kan iemand ook precies uitleggen hoe de verschillende incementaties (of decounteringen) werken? Ik zou het echt op prijs stellen.


Antwoord 1, Autoriteit 100%

Het is geen sprake van voorkeur, maar van logica.

x++Verhoogt de waarde van variabele X na de huidige verklaring verwerken.

++xVerhoogt de waarde van variabele X vóór het verwerken van de huidige verklaring.

Dus beslis gewoon over de logica die u schrijft.

x += ++iWORDT INCROTER IK EN VD I + 1 TOT X toe.
x += i++ZAL I AAN X toevoegen, DAN INCROTER I.


Antwoord 2, Autoriteit 41%

Scott Meyers vertelt u om voorvoegsel voor te geven, behalve in die gelegenheden waar logica dat zou dicteren Postfix is ​​geschikt.

“effectiever C++” Artikel # 6 – dat is voldoende gezag voor mij .

Voor degenen die het boek niet bezitten, zijn hier de relevante aanhalingstekens. Van pagina 32:

Uit uw tijd als C-programmeur herinnert u zich misschien dat de prefixvorm van de increment-operator soms “increment and fetch” wordt genoemd, terwijl de postfix-vorm vaak bekend staat als “fetch and increment”. De twee zinnen zijn belangrijk om te onthouden, omdat ze allemaal fungeren als formele specificaties…

En op pagina 34:

Als jij het soort bent dat zich zorgen maakt over efficiëntie, dan barstte je waarschijnlijk in het zweet toen je de postfix increment-functie voor het eerst zag. Die functie moet een tijdelijk object maken voor zijn retourwaarde en de bovenstaande implementatie creëert ook een expliciet tijdelijk object dat moet worden geconstrueerd en vernietigd. De functie voor het ophogen van het voorvoegsel heeft dergelijke tijdelijke functies niet…


Antwoord 3, autoriteit 21%

Van cppreferencebij het verhogen van iterators:

U zou de voorkeur moeten geven aan pre-increment
operator (++iter) naar post-increment
operator (iter++) als je niet gaat
om de oude waarde te gebruiken. Post-verhoging
wordt over het algemeen als volgt geïmplementeerd:

  Iter operator++(int)   {
     Iter tmp(*this); // store the old value in a temporary object
     ++*this;         // call pre-increment
     return tmp;      // return the old value   }

Het is duidelijk minder efficiënt dan
vooraf verhogen.

Pre-increment genereert het tijdelijke object niet. Dit kan een aanzienlijk verschil maken als uw object duur is om te maken.


Antwoord 4, autoriteit 6%

Ik wil alleen opmerken dat de gegenereerde code hetzelfde is als je pre/post-incrementatie gebruikt waarbij de semantiek (van pre/post) er niet toe doet.

voorbeeld:

pre.cpp:

#include <iostream>
int main()
{
  int i = 13;
  i++;
  for (; i < 42; i++)
    {
      std::cout << i << std::endl;
    }
}

post.cpp:

#include <iostream>
int main()
{
  int i = 13;
  ++i;
  for (; i < 42; ++i)
    {
      std::cout << i << std::endl;
    }
}

_

$> g++ -S pre.cpp
$> g++ -S post.cpp
$> diff pre.s post.s   
1c1
<   .file   "pre.cpp"
---
>   .file   "post.cpp"

Antwoord 5, autoriteit 4%

Het belangrijkste om in gedachten te houden, imo, is dat x++ de waarde moet retourneren voordat de increment daadwerkelijk plaatsvond — daarom moet het een tijdelijke kopie van het object maken (pre-increment). Dit is minder efficiënt dan ++x, dat ter plaatse wordt verhoogd en geretourneerd.

Een ander ding dat het vermelden waard is, is echter dat de meeste compilers in staat zullen zijn om dergelijke onnodige dingen waar mogelijk weg te optimaliseren, beide opties zullen bijvoorbeeld leiden tot dezelfde code hier:

for (int i(0);i<10;++i)
for (int i(0);i<10;i++)

Antwoord 6, autoriteit 4%

Ik ben het eens met @BeowulfOF, maar voor de duidelijkheid zou ik er altijd voor pleiten de verklaringen op te splitsen zodat de logica absoluut duidelijk is, d.w.z.:

i++;
x += i;

of

x += i;
i++;

Dus mijn antwoord is dat als je duidelijke code schrijft, dit er zelden toe doet (en als het ertoe doet, is je code waarschijnlijk niet duidelijk genoeg).


Antwoord 7

Ik wilde even benadrukken dat ++x naar verwachting snelleris dan x++, (vooral als x een object van een willekeurig type is), dus tenzij om logische redenen vereist, ++ x moet worden gebruikt.


Antwoord 8

Postfix-vorm van ++,– operator volgt de regel use-then-change,

Voorvoegselvorm (++x,–x) volgt de regel wijzig-dan-gebruik.

Voorbeeld 1:

Als meerdere waarden worden gecascadeerd met << met behulp van coutdan vinden berekeningen (indien van toepassing) plaats van rechts naar links, maar het afdrukken vindt plaats van links naar rechts, bijv. (if valindien aanvankelijk 10)

cout<< ++val<<" "<< val++<<" "<< val;

zal resulteren in

12    10    10 

Voorbeeld 2:

Als in Turbo C++ meerdere keren ++ of (in welke vorm dan ook) voorkomt in een uitdrukking, dan worden eerst alle prefixvormen berekend, daarna wordt de uitdrukking geëvalueerd en tenslotte worden postfixvormen berekend, bijvoorbeeld

int a=10,b;
b=a++ + ++a + ++a + a;
cout<<b<<a<<endl;

De uitvoer in Turbo C++ zal zijn

48 13

Terwijl het in de moderne compiler wordt uitgevoerd (omdat ze de regels strikt volgen)

45 13
  • Opmerking: meervoudig gebruik van operatoren voor verhogen/verlagen op dezelfde variabele
    in één uitdrukking wordt niet aanbevolen. De behandeling/resultaten van dergelijke
    expressies variëren van compiler tot compiler.

Antwoord 9

Je hebt het verschil goed uitgelegd. Het hangt er gewoon van af of je x wilt verhogen voor elke run door een lus, of daarna. Het hangt af van uw programmalogica, wat geschikt is.

Een belangrijk verschil bij het omgaan met STL-Iterators (die deze operators ook implementeren) is dat het ++ een kopie maakt van het object waarnaar de iterator verwijst, vervolgens verhoogt en vervolgens de kopie retourneert. ++ het daarentegen doet eerst de verhoging en retourneert vervolgens een verwijzing naar het object waarnaar de iterator nu verwijst. Dit is meestal alleen relevant wanneer elk beetje prestatie telt of wanneer u uw eigen STL-iterator implementeert.

Bewerken: de verwisseling van prefix en suffix-notatie opgelost


Antwoord 10

Je vroeg om een voorbeeld:

Deze (orderis een std::vector) zal crashen voor i == order.size()-1op de order[i].size()toegang:

while(i++ < order.size() && order[i].size() > currLvl);

Dit zal nietcrashen bij order[i].size(), omdat iwordt verhoogd, gecontroleerd en de lus wordt verlaten:

while(++i < order.size() && order[i].size() > currLvl);

Antwoord 11

Het begrijpen van de taalsyntaxis is belangrijk bij het overwegen van de duidelijkheid van de code. Overweeg een tekenreeks te kopiëren, bijvoorbeeld met post-increment:

char a[256] = "Hello world!";
char b[256];
int i = 0;
do {
  b[i] = a[i];
} while (a[i++]);

We willen dat de lus wordt uitgevoerd door het nulteken (waarmee wordt getest op false) aan het einde van de tekenreeks. Dat vereist het testen van de waarde pre-increment en ook het verhogen van de index. Maar niet noodzakelijk in die volgorde – een manier om dit te coderen met de pre-increment zou zijn:

int i = -1;
do {
  ++i;
  b[i] = a[i];
} while (a[i]);

Het is een kwestie van smaak wat duidelijker is en als de machine een handvol registers heeft, zouden beide een identieke uitvoeringstijd moeten hebben, zelfs als a[i] een functie is die duur is of bijwerkingen heeft. Een significant verschil kan de uitstapwaarde van de index zijn.

Other episodes