Pętla for - sprawdzanie warunku, wydajność

0

Cześć, mam pytanie o to w jaki sposób kompiluje się pętla for w C++? Chodzi o to, że jeśli mamy taki kod:

for(unsigned i=0; i<tablica.size() - 1; ++i)
   {
   //...
   }

To czy dla tablica.size() - 1 jest tworzona dodatkowa zmienna?
Czy może za każdym "obrotem" pętli wykonywana jest operacja odejmowania?

1

Tak, ale jeśli już masz się czymś martwić to prędzej wywołaniem funkcji size, które, zależnie od kontenera, może nie być tanie.

0

@kq dzięki, ale tak: odpowiedź A, czy tak: odpowiedź B?

A czy w vectorze size() nie jest przypadkiem zdefiniowane inline mniej więcej w taki sposób:

const size_t& size()
   {
   return size;
   }

Wówczas wywołanie size kosztowałoby tyle samo co wpisanie tam każdej innej zmiennej...

0

Jeżeli nie jest to funkcja inline (lub nie jest do niej optymalizowana) to koszt wywołania będzie większy, bo potrzebny jest jeszcze skok do ciała funkcji w miejscu jej wywołania.

1

Skoro size jet wywoływane za każdym obrotem pętli, to oczywiste jest, że jakakolwiek operacja na wyniku tej funkcji też musi być wykonana.

Dla większości standardowych kontenerów size faktycznie jest O(1), ale powiedz mi proszę, jak na podstawie tablica.size() miałem wydedukować, że tablica jest typu std::vector<T>?

Jeśli nie planujesz zmieniać wielkości wektora, to oblicz ilość iteracji raz i do niej przyrównuj. Wywołanie funkcji, a raczej odczyt pamięci z ramu jest znacznie bardziej kosztowne niż wykonanie później operacji odejmowania, bo jest to ok 200 cykli pracy procesora.

0

Och, przejmujemy się odejmowaniem, a nie przejmujemy się wywołaniem funkcji... Jakież to... Jakie to słowo... "premature optimization". Petla (w sumie każda) za każdym obrotem sprawdza warunek, czyli jeśli w warunku masz wywołanie metody, to będzie ona wywołana. Jasne że część kontenerów będzie miała O(1) dla size, ale co z tego jeśli zamiast size co obrót pętli będziesz wykonywać coś o złożoności O(n^3)? Jeśli w trakcie działania pętli nie zmieniasz nic co by wpłynęło na wynik funkcji wywoływanej, znacznie lepiej jest najpierw pobrać i zapisać wynik i w pętli tylko porównywać ze zmienną. look w Effective C++

0
Kowi321 napisał(a):
for(unsigned i=0; i<tablica.size() - 1; ++i)
   {
   //...
   }

Pomijając kwestię optymalizacji, tak napisana pętla to niezły babol, gdy:

tablica.size() == 0
1

Co do oryginalnego pytania, to w teorii będzie to wykonywać się w każdym obrocie pętli (całe wyrażenie po średniku), ale optymalizacje kompilatora prawdopodobnie wykryją, że ta wartość jest niezmienna i stworzą zmienną. W teorii lepiej jest to zrobić ręcznie bo nie zawsze kompilator wszystko rozumie, z drugiej strony jeśli tablica nie jest ogromnie duża to różnica w wykonaniu będzie rzędu mikrosekund

Dodatkowo skoro size() jest uint-em to uint - 1 jest dalej uint czyli dla size() o wartosci 0 po odjęciu 1 dostaniesz maksymalna wartosc uint:
http://ideone.com/DI8DZw

2

Co do oryginalnego pytania, to w teorii będzie to wykonywać się w każdym obrocie pętli (całe wyrażenie po średniku), ale optymalizacje kompilatora prawdopodobnie wykryją, że ta wartość jest niezmienna i stworzą zmienną.

Ja bym powiedział inaczej: funkcja size() zostanie zinline'owana - sprowadzona do odczytu pola klasy (jeśli takie pole w klasie jest), po czym dekrementacja -1 nastąpi raczej w każdej iteracji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1