Obecnie uczę się C ++, a o inkrementacji dowiedziałem się jakiś czas temu. Wiem, że możesz użyć „++ x”, aby dokonać inkrementacji przed i „x ++”, aby zrobić to po.
Mimo to naprawdę nie wiem, kiedy użyć któregokolwiek z tych dwóch… Tak naprawdę nigdy nie użyłem „++ x” i jak dotąd wszystko działało dobrze - więc kiedy powinienem go użyć?
Przykład: Kiedy w pętli for najlepiej jest użyć „++ x”?
Czy ktoś mógłby dokładnie wyjaśnić, jak działają różne przyrosty (lub dekrementacje)? Byłbym naprawdę wdzięczny.
źródło
x++
jest to wartość r o wartościx
przed inkrementacją,x++
to lwartość o wartościx
po inkrementacji. Żadne z wyrażeń nie gwarantuje, że rzeczywista zwiększona wartość zostanie zapisana z powrotem do x, gwarantuje jedynie, że nastąpi to przed następnym punktem sekwencji. „po przetworzeniu bieżącej instrukcji” nie jest ściśle dokładne, ponieważ niektóre wyrażenia mają punkty sekwencji, a niektóre instrukcje są instrukcjami złożonymi.Scott Meyers mówi, żebyś wolał przedrostek, z wyjątkiem tych przypadków, w których logika dyktuje, że ten przyrostek jest odpowiedni.
„Bardziej efektywny C ++” punkt 6 - to dla mnie wystarczający autorytet.
Dla tych, którzy nie są właścicielami książki, oto stosowne cytaty. Od strony 32:
A na stronie 34:
źródło
i++
lub++i
wygenerowany kod jest taki sam.++x
ix++
faktycznie ma znaczenie, o wiele ważniejsze jest, aby faktycznie użyć kompilatora, który może całkowicie i prawidłowo zoptymalizować każdą wersję, bez względu na to, kontekst. „Ponieważ używam tego gównianego starego młotka, mogę wbijać gwoździe tylko pod kątem 43,7 stopnia” to kiepski argument za budowaniem domu przez wbijanie gwoździ pod kątem zaledwie 43,7 stopnia. Użyj lepszego narzędzia.Z cppreference podczas zwiększania iteratorów:
Iter operator++(int) { Iter tmp(*this); // store the old value in a temporary object ++*this; // call pre-increment return tmp; // return the old value }
Preinkrementacja nie generuje tymczasowego obiektu. Może to mieć istotne znaczenie, jeśli tworzenie obiektu jest kosztowne.
źródło
Chcę tylko zauważyć, że kod genowany jest często taki sam, jeśli używasz inkrementacji pre / post, gdzie semantyczny (pre / post) nie ma znaczenia.
przykład:
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"
źródło
std::map::iterator
? Oczywiście te dwa operatory są różne, ale jestem ciekawy, czy kompilator zoptymalizuje przedrostek do przedrostka, jeśli wynik nie zostanie użyty. Nie sądzę, żeby było to dozwolone - biorąc pod uwagę, że wersja postfix może zawierać efekty uboczne.Najważniejszą rzeczą, o której należy pamiętać, imo, jest to, że x ++ musi zwrócić wartość, zanim faktycznie nastąpił przyrost - dlatego musi wykonać tymczasową kopię obiektu (przed inkrementacją). Jest to mniej wydajne niż ++ x, które jest zwiększane w miejscu i zwracane.
Warto jednak wspomnieć, że większość kompilatorów będzie w stanie zoptymalizować takie niepotrzebne rzeczy, gdy tylko będzie to możliwe, na przykład obie opcje będą prowadzić do tego samego kodu tutaj:
for (int i(0);i<10;++i) for (int i(0);i<10;i++)
źródło
Zgadzam się z @BeowulfOF, choć dla jasności zawsze opowiadałbym się za podzieleniem wypowiedzi tak, aby logika była absolutnie jasna, tj .:
lub
Więc moja odpowiedź brzmi: jeśli piszesz czysty kod, to rzadko powinno to mieć znaczenie (a jeśli ma to znaczenie, Twój kod prawdopodobnie nie jest wystarczająco jasny).
źródło
Chciałem tylko ponownie podkreślić, że oczekuje się, że ++ x będzie szybsze niż x ++ (zwłaszcza jeśli x jest obiektem dowolnego typu), więc jeśli nie jest to wymagane ze względów logicznych, powinno być używane ++ x.
źródło
Poprawnie wyjaśniłeś różnicę. Zależy to tylko od tego, czy chcesz, aby x zwiększał się przed każdym przebiegiem pętli, czy po tym. To zależy od logiki programu, co jest właściwe.
Istotną różnicą w pracy z Iteratorami STL (które również implementują te operatory) jest to, że ++ tworzy kopię obiektu, na który wskazuje iterator, następnie zwiększa, a następnie zwraca kopię. ++ Z drugiej strony najpierw dokonuje inkrementacji, a następnie zwraca referencję do obiektu, na który teraz wskazuje iterator. Jest to głównie istotne tylko wtedy, gdy liczy się każda wydajność lub gdy wdrażasz własny iterator STL.
Edycja: naprawiono pomieszanie notacji przedrostków i przyrostków
źródło
Przykład 1:
Gdy wiele wartości są kaskadowo z użyciem << cout następnie obliczeń (jeśli występują) odbywają się od prawej do lewej, ale drukowanie odbywa się od lewej do prawej, np, (jeśli val jeśli początkowo 10)
cout<< ++val<<" "<< val++<<" "<< val;
spowoduje
12 10 10
Przykład 2:
W Turbo C ++, jeśli w wyrażeniu znajduje się wiele wystąpień ++ lub (w dowolnej formie), to najpierw obliczane są wszystkie formy prefiksów, następnie wartościowane jest wyrażenie i na końcu obliczane są formularze przyrostków, np.
int a=10,b; b=a++ + ++a + ++a + a; cout<<b<<a<<endl;
To będzie wyjście w Turbo C ++
48 13
Podczas gdy w dzisiejszym kompilatorze będzie to wynik (ponieważ ściśle przestrzegają zasad)
45 13
wyrażeń różnią się w zależności od kompilatora.
źródło
Zrozumienie składni języka jest ważne przy rozważaniu przejrzystości kodu. Rozważ skopiowanie ciągu znaków, na przykład z post-inkrementacją:
char a[256] = "Hello world!"; char b[256]; int i = 0; do { b[i] = a[i]; } while (a[i++]);
Chcemy, aby pętla była wykonywana poprzez napotkanie znaku zerowego (który testuje fałsz) na końcu łańcucha. Wymaga to przetestowania wartości przed inkrementacją, a także zwiększenia indeksu. Ale niekoniecznie w tej kolejności - sposobem na zakodowanie tego z preinkrementacją byłoby:
int i = -1; do { ++i; b[i] = a[i]; } while (a[i]);
Jest to kwestia gustu, który jest wyraźniejszy i jeśli maszyna ma garść rejestrów, oba powinny mieć identyczny czas wykonania, nawet jeśli [i] jest funkcją, która jest kosztowna lub ma skutki uboczne. Istotną różnicą może być wartość wyjściowa indeksu.
źródło