[C++] inkrementacja

Czy instrukcja i++ to to samo co i=i+1 ?

tak :wink:

czyli i++ najpierw zwraca wartość i a potem dodaje + 1

a ++i najpierw zwiększa wartość i i zwraca już tą powiększoną

Tak, przykładowo masz taki kod:

int i = 5;


cout << i++; // wyświetli się 5

cout << i; // teraz wyświetli się 6

Jeżeli mamy postinkrementację (i++) to wartością tego wyrażenia kiedy posługujemy się std::cout jest jeszcze stara wersja i - potem dopiero następuje zwiększenie o 1.

Oczywiście kiedy nie wypisujemy wartości wyrażenia na ekran, np. jako warunek pętli możemy podać zarówno i++ lub ++i - wtedy to nie ma znaczenia.

A jednak ma znaczenie. Po pierwsze w wyniku operacji ++i lub –i powstaje tak zwana lvalue - czyli właściwie referencja na zmienną i ; Oznacza to że bez problemu skompiluje się i zadziała:

cout<<++++++i; [/code]

zwiększy zmienną i o 3. Natomiast w wyniku operacji i++ oraz i– powstaje stała, więc kod:

[code=php]cout<<i++ ++; 

nawet się nie skompiluje.

O ile zmienna i jest jakimś standardowym typem liczbowym to oczywiście osobno stojąca operacja ++i jest ty samym co i++ a –i jest tym samym co i– (jedynie i++ oraz i– nieco wolniej się kompilują, ale kto by liczył mikrosekundy podczas kompilacji która i tak przebiega najszybszej w kilka sekund), jednak kiedy zmienna i jest obiektem jakieś klasy to już jest olbrzymia różnica, i++ oraz i– są o wiele gorsze. Jeżeli ktoś chcę to mogę tą różnicę wyjaśnić szczegółowo.

Podsumowując… o ile w jakimś konkretnym miejscu programu nie jest istotne którą z operacji użyć, przedrostkowej ( ++i oraz –i ) czy przyrostkowej ( i++ oraz i– ) zawszę należy wybrać formę przedrostkową.

Ważne jest założenie, że i jest typu int/char/short bo jeśli sami to zaimplementujemy to będziemy tak mogli robić. Zresztą, kilkukrotne inkrementowanie w jednej instrukcji jest bez sensu. IMO niepotrzebny cukier składniowy. Lepie użyć operatora +=.

Nie do końca tak jest. Wszystko zależy od tego JAK zaimplementujemy operator przyrostkowy i przedrostkowy. Jeden może robić dużo, a drugi nic i to od nas zależy który wybierzemy. Oczywiście dobrym nawykiem jest trzymanie się konwencji, ale to nie jest wymagane.

Zapomniałeś o long/float/double/long long/unsigned ja to ująłem w kilku słowach standardowe typy liczbowe.

Wcale nie lepiej :stuck_out_tongue: ++++i; będzie szybsze od i+=2; , z tym zwiększaniem o 3 chodziło mi bardziej o łączenia typu (++i)<<=1 gdzie za pomocą += nic nie zrobisz, pokazałem na prostym przykładzie o co z tą lvalue chodzi.

Owszem można zaimplementować operator mnożenia który będzie odejmował, a operator przypisywania który będzie mnożył, ale gdzie w tym sens, kiedy autor postu dojdzie do przeciążania operatorów to sam bez problemu dojdzie do tego co napisałeś, a dopóki nie doszedł to moja rada mu pomoże a twoja o ile będzie próbować zrozumieć - tylko namiesza w głowie. Nie rozumiem poco czepiasz się z tymi bezsensownymi uwagami, posty nabijasz?

Masz rację, nie zauważyłem :wink:

Teraz babola walnąłeś :wink: ++++i będzie w najlepszym przypadku tak samo szybkie jak i += 2 bo i tak wszystko będzie się sprowadzać do add eax, 2, za eax może być inny rejestr lub adres. W release VC++ mi do tego oba przykłady skompilował. Więc szybkość tych dwóch instrukcji jest IDENTYCZNA.

Mówię o tym, bo nie lubię niedopowiedzeń. Wolę gdy mówi się o wszystkich(lub większości) kruczkach. Przypuszczam, że moja rada mu nie namiesza w głowie, tylko wyjaśni, że w C++ “wszystko jest możliwe”.

Teraz to ty się bezsensownie “czepiasz”, posty nabijasz? :wink:

Więc wyłącz optymalizacje w tym VC++ i będzie szybciej, porządne kompilatory po obie te instrukcji optymalizują do dwóch inc eax a bez optymalizacji (w porządnych kompilatorach) ++++i szybsze, zanim walniesz kolejnego babola, może najpierw sprawdź pisząc krótkiego testa w assembler’ze, albo poczytaj jakie są czasy wykonania tych instrukcji.

Twoi wypowiedzi zabrzmiały tak jakby się nie zgadzałeś z tym co napisałem. W sumie sprowadza się to do tego, że albo lepiej użyć przedrostkowej formy (no chyba że algorytm wymaga) albo ta klasa napisana bez sensu i lepiej wcale jej nie używać. Co do teoretycznych możliwości to rzeczywiście można zaimplementować jakąś klasę tak że przedrostkowa forma będzie sto albo nawet milion razy wolniejsza od przyrostkowej.

Teraz mi powiedz, co będzie szybsze:

inc eax

inc eax

inc eax

inc eax

* czy

add eax, 4

**?

To te Twoje “optymalizacje” raczej spowolnią kod. Podsumowując inc jest szybszy tylko dla 2 wywołań, przy 3 jest tak samo szybki jak add, a przy większej ilości jest wolniejszy od add.

* - wg Twojej tabelki cztery cykle.

** - wg Twojej tabelki trzy cykle.

Już przy zwiększaniu o 3 instrukcje inc ma sens zamienić na add , owszem czas ten sam, zaś wersja z add zajmuje mniej miejsca w pamięci :smiley: Oczywiste chyba jest że im więcej tych operacji inc tym bardziej się opłaca zamienić na add. Jednak przy zwiększaniu o 1 lub o 2 inc jest lepsza niż add. Poza tym chciał bym zobaczyć jak w następującym kodzie zamienisz ++++i na i+=2 :stuck_out_tongue:

#include 
#include 
#include 
using namespace std;

int main()
  {
   int dane[]={1,2,3,4,5,6,7,8};
   list<int> T(dane,dane+8);
   for(list<int>::iterator i=T.begin();i!=T.end();++++i) cout<<setw(2)<<*i;
   cin.get();
   return 0;
  } [/code]

Powyższe mogłeś sam wywnioskować z przedstawionej tabelki, z postów co zazwyczaj piszesz raczej wynika że masz głowę na karku, nie rozumiem poco tu udajesz kogoś kim nie jesteś.