C++, Operator zwiększania

0

Witam,
który operator zadziała szybciej:
++i

czy i++

i dlaczego?

0

W tym pierwszy od razu zwiekszana jest wartosc,a w i++ to dopiero w nastepnym kroku widac ze jest zwiększona.

0

Przy ++A najpierw wykonywana zostaje operacja inkrementacji, potem zwracana jest wartość zmiennej.

Przy A++ Pierw zwracana jest wartość zmiennej, potem dokonywana operacja inkrementacji.

Nie ma różnicy w działaniu pod względem prędkości, różnica jest w zwracanej wartości.

0

To zalezy jesli chodzi o typy wbudowane to maja porownywalna predkość (chodź chyba ++i i tak jest ciut szybszy ). Jeśli natomiast chodzi o typy tworzone przez użytkonika to ++i jest bezsprzecznie szybsze niż i++. Dlaczego ? Poczytaj troche o przeciążaniu tych dwoch operatorów to zrozumiesz różnice.

0

@xxxxxx: Poczytaj troche jak wygladaja te operatory w asmie to zobaczysz, ze roznicy w predkosci nie ma...

0
johny_bravo napisał(a)

@xxxxxx: Poczytaj troche jak wygladaja te operatory w asmie to zobaczysz, ze roznicy w predkosci nie ma...

Dla typów prostych tak, to praktycznie nie ma znaczenia, ale iteratorów już może mieć - w przypadku It++ tworzona jest kopia.

--- edit ---

int i=0;
string text("tralala");
string::iterator it=text.begin();

while(it!=text.end())
{
    cout<<*it<<endl;
    it++;
    i++;
}

while(it!=text.end())
{
    cout<<*it<<endl;
    ++it;
    ++i;
}

W obu przypadkach na VC to absolutnie nie ma znaczenia - kod asemblerowy jest identyczny.

0

W obu przypadkach na VC to absolutnie nie ma znaczenia - kod asemblerowy jest identyczny

to ładnie operator napisali. Ale czasem, jak jest jakiś skomplikowany obiekt, to nie ma bata - trzeba stary stan zapamiętać, zmodyfikować obiekt i zwrócić "wspomnienie". Wtedy, jeśli kompilator nie ma jakiejś agresywnej optymalizacji, może być narzut - szczególnie, jeśli jeszcze konstruktor kopiujący nie jest trywialny.

btw: w jakiejś książce o czystym C czytałem dyskusję nt typów wbudowanych. Mianowicie zmienna++ daje podobno większą swobodę optymalizatorowi, no bo sam może zdecydować, kiedy to zwiększenie wykonać (zaraz po zwróceniu wartości, trochę później, albo i duużo później: dopiero podczas kolejnego odczytu zmienna) - to może pozwolić na agresywniejszą optymalizację (np w ogóle nie zmieni wartości zmiennej, jeśli nigdzie później ta wartość nie jest używana). ++zmienna ogranicza tutaj optymalizator: modyfikacja musi nastąpić u i właśnie tu.

0
Ranides napisał(a)

to ładnie operator napisali. Ale czasem, jak jest jakiś skomplikowany obiekt, to nie ma bata - trzeba stary stan zapamiętać, zmodyfikować obiekt i zwrócić "wspomnienie".

Tak, tylko zwróć uwagę, że stara wersja It nie jest nigdzie wykorzystywana więc kompilator usunął deklarację i inicjalizację obiektu tymczasowego (sprytny kompilator poszukałby operatora preinkrementacji :)) Prawdopodobnie w przypadku bardziej skomplikowanych iteratorów wyglądałoby to podobnie. Dodam, że operator++ z przykładu został ładnie wmiksowany w rozwinięty kod cout - nie dało się ustawić breakpoint'a.

0

więc kompilator usunął deklarację i inicjalizację obiektu tymczasowego (sprytny kompilator poszukałby operatora preinkrementacji :))

a co by się działo, gdyby inicjalizacja miała efekty uboczne? takie coś przejdzie tylko wtedy, kiedy używasz do zachowania stanu automatycznie wygenerowanego konstruktora kopiującego / operatora przypisania . Jak zdefiniujesz dla klasy własny, to jego wywołanie jest gwarantowane. Ale to, co opisałeś, to i tak bardzo dużo i przyznaję, tak od razu o tym nie pomyślałem.

Dodam, że operator++ z przykładu został ładnie wmiksowany w rozwinięty kod cout - nie dało się ustawić breakpoint'a.

mów mi więcej. ja śledzę debugerem tylko niezoptymalizowany kod z wyłączonym wszystkim (w tym inline'ami), bo bym się pogubił całkiem. A co się dzieje w wersji release, to już pojęcia nie mam ;)

0
Ranides napisał(a)

a co by się działo, gdyby inicjalizacja miała efekty uboczne? takie coś przejdzie tylko wtedy, kiedy używasz do zachowania stanu automatycznie wygenerowanego konstruktora kopiującego / operatora przypisania . Jak zdefiniujesz dla klasy własny, to jego wywołanie jest gwarantowane. Ale to, co opisałeś, to i tak bardzo dużo i przyznaję, tak od razu o tym nie pomyślałem.

Nie no wiadomo, że nie zawsze się da usunąć deklaracje/inicjalizacje obiektu. W sumie to tylko kompilator ;)

mów mi więcej. ja śledzę debugerem tylko niezoptymalizowany kod z wyłączonym wszystkim (w tym inline'ami), bo bym się pogubił całkiem. A co się dzieje w wersji release, to już pojęcia nie mam ;)

Heh to fakt, kod wygląda zupełnie inaczej ;) Np. iterator stringa to zwykły wskaźnik. Ale sprawdziłem dla list<string> i:

list<string>::iterator it=lista.begin();

while(it!=lista.end())
{
    cout<<*it;
    it++;
}

//*** asm ***
//  while(it!=lista.end())
0040409B  cmp         esi,edi 
0040409D  je          main+1B7h (4040B7h) 
0040409F  nop              
//  {
//      cout<<*it;
004040A0  lea         ecx,[esi+8] 
004040A3  push        ecx  
004040A4  push        offset std::cout (417218h) 
004040A9  call        std::operator<<<char,std::char_traits<char>,std::allocator<char> > (401D00h) 
//      it++;
004040AE  mov         esi,dword ptr [esi] //<--- it=it->next
004040B0  add         esp,8 

004040B3  cmp         esi,edi //<---  while(it!=lista.end())
004040B5  jne         main+1A0h (4040A0h) 
//  }

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