Archief - [C++] i++ vs ++i & oneindige loop

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

Curahee Q

Legacy Member
Beste 9livers

In mijn cursus, en in de les, werd er vermeld dat je bij bijvoorbeeld volgende code

Code:
while(i < 10) {
      ++i;
}
(Ja een for-loop is beter, maar dit is gewoon een voorbeeld)

Je dus beter ++i gebruikt in plaats van i++. Echter staat er nergens in waarom dat zo is, best lame imo.

Als 2de vraag, in de cursus staat ook dat je voor een oneindige loop het volgende gebruikt

Code:
for(; ;) {
      ...
}

In een labo gebruikte ik dan gewoon

Code:
while(true) {
      ...
}

Dat was goed (heb het hem gevraagd), maar waarom in godsnaam met een for-loop? Die while lijkt me toch veel logischer?

Alvast bedankt

Yen

Legacy Member
Curahee Q zei:
Beste 9livers

In mijn cursus, en in de les, werd er vermeld dat je bij bijvoorbeeld volgende code

Code:
while(i < 10) {
      ++i;
}
(Ja een for-loop is beter, maar dit is gewoon een voorbeeld)

Je dus beter ++i gebruikt in plaats van i++. Echter staat er nergens in waarom dat zo is, best lame imo.
Of ++i beter is als i++ hangt er vanaf wat je wilt doen. Bij ++i zal de waarde van i verhogen voor de expressie en bij i++ zal de waarde van i verhogen na de expressie.

Curahee Q zei:
Als 2de vraag, in de cursus staat ook dat je voor een oneindige loop het volgende gebruikt

Code:
for(; ;) {
      ...
}

In een labo gebruikte ik dan gewoon

Code:
while(true) {
      ...
}

Dat was goed (heb het hem gevraagd), maar waarom in godsnaam met een for-loop? Die while lijkt me toch veel logischer?

Alvast bedankt
Ik gebruik meestal while (1) { ... }. Eigenlijk maakt het niet uit, gebruik wat voor u het duidelijkste is.

Cycloon

Legacy Member
i++ en ++i maken als single statement totaal geen verschil. Waarom het beter zou zijn is mij ook een raadsel.

for( ; ; ) is hetzelfde als while(true) en hetzelfde als while(1) en hetzelfde als while(3==3). Het is gewoon een andere schrijfwijze.

Gurdt

Legacy Member
i++ en ++i maken wel degelijk (een minuscuul) verschil, hoewel ik zou vermoeden dat compilers dat wel optimaliseren :) het zit namelijk zo:
- als je ++i doet, gaat die integer met 1 verhoogd worden, punt uit.
- als je i++ doet gaat die operator eerst een kopie van i maken, de originele met 1 verhogen en dan de kopie teruggeven (je krijgt dus de oude i terug). Dit heeft als nadeel dat i++ een kopieer-operatie gaat uitvoeren die nutteloos is in jouw geval (de originele i wordt niet opgevangen en dus niet meer gebruikt). Zo een kopieer-operatie is natuurlijk geen drama maar het is de idee :)

Met die while-lus gaat dat volgens mij het volgende zijn:
- bij een while-lus wordt voor elke uitvoering de conditie gecontroleerd die tussen de haakjes staat, die conditie staat dan voor een booleaanse waarde (true/false).
- bij een for-lus zijn er 3 opdrachten die uitgevoerd worden. De eerste op het begin, de 2e voor elke iteratie, de 3e na elke iteratie. Zo kan je ook meerdere opdrachten in zo 1 van die 3 opdrachten steken (kijk ook eens hier: The for loop with a comma operator : For statementStatementC Tutorial). En volgens mij bedoelt jouw leerkracht dat de 2e opdracht leeg is (; staat voor een lege opdracht, ;;; zijn dus gewoon 3 lege opdrachten) en dat daarom niet gecontroleerd hoeft te worden of iets waar of niet waar is (true/false), wat natuurlijk wel gebeurt bij de while-lus.

Natuurlijk dit zijn allemaal zeer minimale dingen die theoretisch wel een verschil maken, maar in de praktijk denk ik niet dat iemand naar zulke dingen kijkt :) in de praktijk draait het allemaal om leesbaarheid van de code. Zo is while(true) stukken leuker om te lezen dan for(;;;). Althans dat vind ik ;)

forloRn_

Legacy Member
Als het in je cursus staat, onthou je dat gewoon voor het examen en daarna mag je het zo snel mogelijk vergeten. Negen van de tien is je compiler slim genoeg om de meest efficiënte code te genereren, onafhankelijk van de schrijfwijze. Performantiegewijs zal het geen lor uitmaken en zelfs als het iets zou uitmaken, moet je je de vraag stellen of het wel de moeite is om leesbaarheid op te offeren voor een paar luttele nanoseconden (meestal niet dus).

Leuk om mee uit te pakken op feestjes of om je cursus vol te krijgen, maar verder is het volstrekt nutteloze kennis hoor.

Dat gezegd zijnde, gebruik ik ook altijd while (true) en i++, omdat dat er mooier uitziet.

Cycloon

Legacy Member
Gurdt zei:
- als je ++i doet, gaat die integer met 1 verhoogd worden, punt uit.

En jij denkt dat een CPU zomaar +1 kan doen direct in het ram geheugen? Die variabele gaat ook eerst in het register komen, daarna verhoogd worden en daarna terug weggeschreven worden (als we even vergeten dat er cache is e.d.).

Beide statements maken géén verschil als die alleen staat op 1 regel.

Gurdt

Legacy Member
Jongens, zijn jullie daar weer, volstrekt nutteloze kennis? Waarom? Omdat het eens iets theoretischer is? Als gij met dikke klasses werkt gaat ge ook moeten opletten of ge de postfix of prefix notatie gaat gebruiken omdat ge anders wél de copy-constructor gaat gebruiken, en dat gaat uw compiler NIET optimaliseren.
Ik zeg er ook zelf bij dat het amper een aars verschil maakt maar dat ik gewoon ff de idee erachter probeer uit te leggen.

Nu ik moet toegeven, ik dacht nog wel toen ik het schreef gisteren: jop, nu gaan morgen die 2 kerels weer liggen afgeven daarop, omdat die dat áltijd doen.

--

Om te beginnen, geen enkele kennis is volstrekt nutteloos, dus daar ga je al de mist in. En ten tweede, op feestjes pak ik niet uit met informatica-dingen, ik weet niet hoe zit bij jullie, maar ik heb dan betere dingen te doen, en nee, meisjes vinden dat niet geil.

Vervolgens, Cycloon, denkt gij nu echt, dat ik niet weet hoe een CPU werkt? Of dat ik nog nooit van dingen als Assembler gehoord heb? Troost u, ik heb in het eerste jaar van mijn opleiding een assembler-interpreter geschreven, voor jullie: dat betekent dat ik een programma heb gemaakt dat precies hetzelfde doet als een CPU.
Dus ik weet wel wat een register en dergelijke is :)

Tot slot: beide statements maken geen verschil (net zoals ik al zei, leer eens even lezen jongens) INDIEN de compiler dat optimaliseert. En bij custom klassen zal dat niet het geval zijn ;) geloof me maar.

Nu, volgend semester begin ik met het vak compilers (ja dat is weer iets theoretischer, sorry), dus ik hou jullie op de hoogte, hoe het zit met dat optimaliseren van ++i en i++.

--

Trouwens, ik vind persoonlijk ++i mooier dan i++ ^^ maar dat is een kwestie van smaak neem ik aan?

Cycloon

Legacy Member
Zoals steeds, je moet je niet zo aanstellen en aangevallen voelen. Zoals jij het stelde sloeg het op niet veel.

En je probeert nog steeds je gelijk te halen, maar i++ en ++i zijn totaal gelijk. Daar heeft compileroptimalisatie nog steeds geen fluit mee te maken.

En I don't care of jij iets van de werking van een CPU kent tbh. Ik verspreidde maar wat kennis, als jij daar geen boodschap aan hebt negeer dat dan gewoon? Je lijkt wel een gefrustreerde tiener ofzo :s

En tof dat je volgend semester een vak over compilers volgt, toevallig ik ook, maar ik zie het nut niet in van dit hier te lopen verkondigen.

++i; == i++; :)

Btw, wow dat je een assembler interpreter hebt geschreven, jij bent mijn held voor vandaag! :love:

Gurdt

Legacy Member
Ok, als ++i en i++ voor u identiek gelijk zijn, mag je voor mijn part de rest van uw leven falen.

Wat gij zegt is zo belachelijk dat ik precies door begin te krijgen met wat voor mensen ik hier bezig ben :)

Je verspreidde maar wat kennis? Niet aangevallen voelen?
Ik zeg dat ++i de integer i met 1 gaat verhogen en jij begint hier omhoog te schijten met CPU en RAM :/

Zoals ik eerder al zei, ik zie jou enorm vaak in andere threads, altijd maar liggen bashen en onnozele meningen geven (zoals hierboven beweren dat ++i en i++ hetzelfde is).
Het is niet omdat JIJ op school of werk niet zulke dingen hebt gezien, dat het niet zo IS. Er zijn nog vele dingen die jij en ik niet weten, maar dat wordt hier precies niet zo goed beseft. Alles wat uit uw mond komt is hier blijkbaar de waarheid?

Wel: i++ en ++i zijn NIET hetzelfde :) leg je er bij neer jongen.

En ik reageer als een gefrustreerde tiener omdat jij alle informatica-gerelateerde topics verziekt met uw onnozel gedrag altijd.

Tyfius

Legacy Member
Cycloon zei:
En je probeert nog steeds je gelijk te halen, maar i++ en ++i zijn totaal gelijk. Daar heeft compileroptimalisatie nog steeds geen fluit mee te maken.

++i; == i++; :)
Compiler optimalisatie heeft daar alles mee te maken. Het is die die gaat beslissen dat voor built-in types (indien mogelijk) dergelijke operaties die op zich staan dezelfde output gaan hebben en dus op dezelfde manier kunnen worden geoptimaliseerd.
Code:
int main(int argc, char *argv[])
{
  int i = 0;
  i++;
  ++i;
  i += 1;
  i = i + 1;
}
Dit zal in alle 4 de gevallen door een deftige compiler naar hetzelfde worden vertaald, iets als:
Code:
  call	___main
  movl	$0, -4(%ebp)
  leal	-4(%ebp), %eax
  incl	(%eax)
  leal	-4(%ebp), %eax
  incl	(%eax)
  leal	-4(%ebp), %eax
  incl	(%eax)
  leal	-4(%ebp), %eax
  incl	(%eax)
  movl	$0, %eax
  leave
  ret
Merk op dat in alle gevallen hetzelfde blok wordt gebruikt:
Code:
  leal	-4(%ebp), %eax
  incl	(%eax)
Er is natuurlijk een verschil wanneer dit onderdeel is van een statement.
Code:
i, j = 3;
x = i++; // x == 3, i == 4
y = ++i; // y == 4, j == 4
Tot slot, wanneer je met iterators of ++ overloads op custom classen zit dan is ++object veel performanter dan object++ omdat de compiler dat daar niet kan optimaliseren en dus bij de postfix operator een tijdelijk object gaat aanmaken.

edit:
And if all else fails: [13.15] Which is more efficient: i++ or ++i?

Cycloon

Legacy Member
i++ en ++i zijn als single statement wel identiek qua performantie.

If there is no surrounding expression, if the ++i or i++ appears all by itself, to increment i and do nothing else, you can use either form; it makes no difference.
7.2 Increment and Decrement Operators

The performances of prefix and postfix versions are basically identical (at least if the return value is not used).

There is definitely no difference between ++i and i++ if they are used as statements on their own.
Core Java - What's the "performance" difference between i++ and ++i? 2 senarios:1. i++; vs ++i;2. int j = i++; v

Jij bent gewoon over andere zaken bezig, bv volgorde van de uitvoering van het increment, toepassing op objecten, maar dat is hier niet aan de orde in het gegeven voorbeeld.

Gurdt

Legacy Member
Jezus cycloon, leest gij ook posts? We zeggen allebei net dat de compiler idd i++ en ++i zal optimaliseren maar dat dat NIET het geval is bij klasses of in een expressie.

Nu komt gij WEER af met die zever van: jama als er niks staat en i is een integer, dan is i++ en ++i WEL hetzelfde!!

Ja da is zo, lees ook eens andere posts...

forloRn_

Legacy Member
Ik ging me er normaal van af maken met hoofdzaken en bijzaken en zo, maar je moest weer koppig zijn.

Code:
#include <iostream>

using namespace std;

int main() {
	class C {
	public:
		C() {}
		C(const C & that) { cout << "copy ctor" << endl; }

		C & operator++() { return *this; }		// prefix
		C & operator++(int) { return *this; }	// postfix
	};

	cout << "explicit copy:" << endl;
	C c;
	C d(c);

	cout << "++c:" << endl;
	++c;

	cout << "c++:" << endl;
	c++;
}

Voer uit en interpreteer.

Er is geen reden om de copy constructor aan te roepen als je de return value toch niet gebruikt, en de reden om een onderscheid te maken tussen prefix ++ en postfix ++ bij klassen is omdat het aparte methods zijn.

Curahee Q

Legacy Member
Ik vind dat er gerust mag verwezen worden naar de meer theoretische kant van de zaak, die interesseert me namelijk ook.

Dus in het algemeen kunnen we stellen dat ++i sneller is dan i++, behalve als het om pure integers gaat. Als je dan bijvoorbeeld met pointers gaat werken kan je beter ++i doen?

Code:
vector<string>::iterator it = v.begin();

while(it != v.end()) {
      
      ++it;                      // sneller dan it++; ?
}

Is dit dan effectief sneller dan it++ omdat bij ++it de iterator niet wordt gekopieerd?

Gurdt

Legacy Member
forloRn_ zei:
Ik ging me er normaal van af maken met hoofdzaken en bijzaken en zo, maar je moest weer koppig zijn.

Code:
zinloze code

Voer uit en interpreteer.

Er is geen reden om de copy constructor aan te roepen als je de return value toch niet gebruikt, en de reden om een onderscheid te maken tussen prefix ++ en postfix ++ bij klassen is omdat het aparte methods zijn.

Wat wil je nu eigenlijk aantonen? Dat de copy-constructor in totaal slechts 1 keer wordt opgeroepen? Wel: uw post-fix functie is ook gewoon fout :)

beter zou zijn:

Code:
#include <iostream>

using namespace std;

int main() {
	class C {
	public:
		C() {}
		C(const C & that) { cout << "copy ctor" << endl; }

		C & operator++() { return *this; }		// prefix
		C & operator++(int) //postfix
		{
			//kopie aanmaken
			C copy(*this);

			//this verhogen
			//...

			//kopie teruggeven
			return copy;
		}
	};

	cout << "explicit copy:" << endl;
	C c;
	C d(c);

	cout << "++c:" << endl;
	++c;

	cout << "c++:" << endl;
	c++;
}

voer uit, en interpreteer

Cycloon

Legacy Member
Curahee Q zei:
Dus in het algemeen kunnen we stellen dat ++i sneller is dan i++, behalve als het om pure integers gaat. Als je dan bijvoorbeeld met pointers gaat werken kan je beter ++i doen?

Is dit dan effectief sneller dan it++ omdat bij ++it de iterator niet wordt gekopieerd?

Voor primitieve types: Niks van aantrekken.
Voor klassen: Afhankelijk van implementatie/compiler.

Natuurlijk, vanaf je gaat toekennen of gebruiken als argumenten moet je zelf goed bedenken wat je wil, want het incrementeren gebeurt op een verschillend moment.

++it gaat sneller zijn zonder compiler optimalisatie (omdat het hier over een object gaat). Met compiler optimalisatie merk je geen verschil. (verschil zal wel énorm klein zijn in performantiewinst).

Gurdt

Legacy Member
Curahee Q zei:
Ik vind dat er gerust mag verwezen worden naar de meer theoretische kant van de zaak, die interesseert me namelijk ook.

Dus in het algemeen kunnen we stellen dat ++i sneller is dan i++, behalve als het om pure integers gaat. Als je dan bijvoorbeeld met pointers gaat werken kan je beter ++i doen?

Code:
vector<string>::iterator it = v.begin();

while(it != v.end()) {
      
      ++it;                      // sneller dan it++; ?
}

Is dit dan effectief sneller dan it++ omdat bij ++it de iterator niet wordt gekopieerd?

Ja, ma wederom, da verschil gaat ge in de praktijk nie merken, maar ge kunt even snel ++it schrijven als it++, dus waarom niet ;) minder leesbaar is het niet vind ik.

Nu, ++i is zoals deze discussie zegt, niet altijd sneller dan i++, maar zeker nooit trager, en meestal wel sneller ;)

Tyfius

Legacy Member
forloRn_ zei:
Ik ging me er normaal van af maken met hoofdzaken en bijzaken en zo, maar je moest weer koppig zijn.

Code:
#include <iostream>

using namespace std;

int main() {
	class C {
	public:
		C() {}
		C(const C & that) { cout << "copy ctor" << endl; }

		C & operator++() { return *this; }		// prefix
		C & operator++(int) { return *this; }	// postfix
	};

	cout << "explicit copy:" << endl;
	C c;
	C d(c);

	cout << "++c:" << endl;
	++c;

	cout << "c++:" << endl;
	c++;
}

Voer uit en interpreteer.

Er is geen reden om de copy constructor aan te roepen als je de return value toch niet gebruikt, en de reden om een onderscheid te maken tussen prefix ++ en postfix ++ bij klassen is omdat het aparte methods zijn.
Ik ben niet helemaal zeker wat het punt is dat je wou maken, maar ik ga hier even verder op gaan om toch te vertellen dat er een verschil is, puur uit interesse en de volledigheid. :)

Wanneer ik deze code uitvoer krijg ik hetvolgende:
Code:
jensen@atlantis:~/Desktop$ ./a.out 
explicit copy:
copy ctor
++c:
c++:

Echter, wanneer we de assembly gaan analyzeren zien we het volgende (ik heb even de relevante stukken er uit gehaald):
Code:
_ZZ4mainEN1CppEv:
.LFB959:
	pushq	%rbp
.LCFI2:
	movq	%rsp, %rbp
.LCFI3:
	movq	%rdi, -8(%rbp)
	movq	-8(%rbp), %rax
	leave
	ret

_ZZ4mainEN1CppEi:
.LFB960:
	pushq	%rbp
.LCFI4:
	movq	%rsp, %rbp
.LCFI5:
	movq	%rdi, -8(%rbp)
	movl	%esi, -12(%rbp)
	movq	-8(%rbp), %rax
	leave
	ret

.LC2:
	.string	"++c:"
.LC3:
	.string	"c++:"
	.text

main:
movl	$.LC2, %esi
	movl	$_ZSt4cout, %edi
	call	_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
	movq	%rax, %rdi
	movl	$_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
	call	_ZNSolsEPFRSoS_E
	leaq	-1(%rbp), %rdi
	call	_ZZ4mainEN1CppEv
	movl	$.LC3, %esi
	movl	$_ZSt4cout, %edi
	call	_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
	movq	%rax, %rdi
	movl	$_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
	call	_ZNSolsEPFRSoS_E
	leaq	-1(%rbp), %rdi
	movl	$0, %esi
	call	_ZZ4mainEN1CppEi

Zoals je hier kan zien wordt er bij de 2de call wel een extra instructie gedaan, namelijk de movl $0, %esi die dan door _ZZ4mainEN1CppEi wordt gebruikt waar dat bij _ZZ4mainEN1CppEv niet het geval is.

Maar zoals eerder al gezegd, in de praktijk zijn dergelijke dingen verwaarloosbaar. Ik denk dat bij de eerste versies van de Apollo software dergelijke dingen misschien van belang waren, maar vandaag de dag maalt niemand daar nog echt om.

En om even op die while() issues te antwoorden. while (true) is inderdaad iets duidelijker dan die for constructie. Het belangrijkste deel van je code is de leesbaarheid, en daar wint het while statement. Dit gezegd zijnde is while (true) niet echt de beste oplossing, het is beter een boolean waarde te gebruiken die je op false kan zetten wanneer de loop moet eindigen. Zeker wanneer er later threads ter sprake komen is dat een veel propere manier op die te laten stoppen dan die te aborten.

Curahee Q

Legacy Member
Wat betreft die oneindige lus. Het was effectief een programma dat oneindig moest draaien, dus was het niet de bedoeling om het af te breken.

Maar je hebt inderdaad wel gelijk, zal er in de toekomst aan denken als er threads aan te pas komen. Want break mogen we in het school niet gebruiken dus moet het inderdaad moet een variable die je op false kan zetten.

forloRn_

Legacy Member
Gurdt zei:

Ja vriend, maar je schrijft wel zélf de copy en daar kan die arme postfix ++ niks aan doen. Ik ben niet begonnen over copy constructors en temporaries, dat zijn jullie geweest.

Tot nu toe zitten we dus op één instructie verschil tussen prefix en postfix, die misschien zelfs wegvalt als je de optimization hoger zet. Mijn punt was dat het uiteindelijk geen lor uitmaakt, wat was het jouwe weer?
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan