[#1] Klasa::getA() - narzut?
Mam trochę głupie pytanie do C++ masterów. Załóżmy, że klasa w C++ wygląda mniej więcej tak:

class Klasa
{
public:
    int a;
    
    int getA();
};


int Klasa::getA()
{
    return a;
}



Mam obiekt tej klasy:

Klasa obiekt1;


Może mi ktoś powiedzieć czy pobranie wartości zmiennej "a" bezpośrednio, czyli tak:

int b = obiekt1.a;


jest bardziej efektywne (szybsze) niż w ten sposób:

int b = obiekt1.getA();


?

Nie wiem czy decydować na stosowanie tych "getterów" i "setterów" czy to może jednak trochę odbija się na prędkości i lepiej operować (oczywiście w miarę możliwości) bezpośrednio na zmiennych składowych obiektu klasy? A może kompilator potrafi sobie z tym poradzić i sprawia, że nie ma różnicy między tymi dwoma sposobami pobierania wartości elementów składowych obiektu?

Przyznam się, że w tym co teraz robię pasowałyby mi takie "gettery", bo przy pobieraniu wartości coś tam sprawdzam w przypadku negatywnego rezultatu coś tam muszę zrobić. No ale ten "getter" byłby wywoływany bardzo często w bardzo wrażliwym na prędkość miejscu więc chciałbym mieć świadomość tego, że używając go mam jakis narzut z tym związany.

Orientuje się ktoś jak to jest?

[#2] Re: Klasa::getA() - narzut?

@MDW, post #1

Nie wiem czy decydować na stosowanie tych "getterów" i "setterów" czy to może jednak trochę odbija się na prędkości i lepiej operować (oczywiście w miarę możliwości) bezpośrednio na zmiennych składowych obiektu klasy?

Bezpośrednie pobieranie zawartości zmiennej jest zawsze szybsze, ale kłóci się odrobinę z ideą obiektowości (enkapsulacja). Settery i gettery są na pewno bardziej eleganckie, łatwiej jest wprowadzać zmiany w kodzie - jak zmienisz nazwę zmiennej a, bądź zmienisz konstrukcję zachowywania informacji (np. umieścisz a w jakiejś strukturze), to wystarczy że zmienisz konstrukcję metody GetA(), reszty kodu korzystającego z klasy wtedy ruszać nie musisz.
Coś za coś. ;)

[#3] Re: Klasa::getA() - narzut?

@MinisterQ, post #2

Dzięki za odpowiedź.

Pewnie, że get() jest dużo bardziej eleganckim i uniwersalnym rozwiązaniem. Jednak zastanawiam się czy warto coś takiego stosowac jeżeli odwołania będą się wykonaywały niemalże cały czas. Ciekawe jak duży jest ten narzut. W chacie może zrobię sobie taki mały test. Myślisz, że narzut jest tego rzędu, że będzie aż zauważalny powiedzmy przy 100 000 pobrań wartości zmiennej? Mówię o procesorze G4/1000, bo innego nie mam. Chciałem kupić NatAmi ale ona nie ma AGP. ;) ;) ;)

[#4] Re: Klasa::getA() - narzut?

@MDW, post #1

Niewolniejsze będzie bezpośrednie, gdy metoda będzie inline, będzie to to samo, tylko ładniej opakowane, dodatkowo wtedy, polecam zmienne zrobic protected. Nie będzie problemu z przypadkową zmianą wartości z zewnątrz.

[#5] Re: Klasa::getA() - narzut?

@MDW, post #3

Szczerze mówiąc nie wiem, trzeba by wykonać jakieś testy...

[#6] Re: Klasa::getA() - narzut?

@MinisterQ, post #5

Zależy czy kompilator zoptymalizuje, zawsze można użyć metod inline jako getterów/setterów.

[#7] Re: Klasa::getA() - narzut?

@Kaczus, post #4

Niewolniejsze będzie bezpośrednie

Że co? Bezpośrednie odwołanie się do zmiennych klasy będzie najwolniejsze?

Inline to faktycznie dobry pomysł. Co prawda oprócz samego pobrania wartości zmiennej chcę tam wrzucić dwa warunki i wywołanie dwóch funkcji ale tyle chyba jeszcze wypada wcisnąć do metody inline, prawda?

[#8] Re: Klasa::getA() - narzut?

@Kaczus, post #4

Właściwie nie wiem co chciałeś przez to powiedzieć. ;)

[#9] Re: Klasa::getA() - narzut?

@MDW, post #7

Nie może być najwolniejsze, na chłopski rozum wywołanie funkcji która pobiera jakąś zmienną i i ją zwraca to jest zawsze kilka(naście) instrukcji procesora więcej niż tylko pobranie wartości zmiennej z innej części kodu...

Ciężko porównywać np. javę z c++ w tym przypadku, ale szybkość kodu w javie, który pobiera zawartość zmiennej można podzielić w taki sposób (od najszybszego do najwolniejszego):

-pobranie zawartości ze statycznego obiektu klasy
-pobranie zawartości przez stworzony obiekt klasy
-pobranie zawartości przez metodę która zwraca tą wartość

[#10] Re: Klasa::getA() - narzut?

@MDW, post #7

Niewolniejsze - taki potworek slowny - nierówność nieostra :)

[#11] Re: Klasa::getA() - narzut?

@MinisterQ, post #8

szybkość odwolania bezpośredniego bedzie albo szybszy, albo tak samo szybki jak wywołanie metody, jeśli metoda będzie inlinowa, będzie tak samo szybko.

[#12] Re: Klasa::getA() - narzut?

@Kaczus, post #11

Ja tam bym się wolał na własnej skórze przekonać, bo coś mi się nie chce w to wierzyć z powodów które napisałem wyżej.

[#13] Re: Klasa::getA() - narzut?

@MinisterQ, post #12

Java działa troszkę inaczej, tu, w przypadku inline wstawiana jest zawartość metody, jeśli metoda ma jedynie return a, to bedzie wstawiona wartość a - do tego zdeterminuje się kod w asemblerze, jeśli metoda nie byłaby inline, to jedynie można by liczyć na dobry optymalizator.

[#14] Re: Klasa::getA() - narzut?

@Kaczus, post #10

Niewolniejsze - taki potworek slowny - nierówność nieostra :)

Aaaaa, hehehe. Nie zauważyłem. Teraz się zgadza. :)

[#15] Re: Klasa::getA() - narzut?

@MinisterQ, post #12

Ja tam bym się wolał na własnej skórze przekonać, bo coś mi się nie chce w to wierzyć

Za dużo Javy pewnie... Ja postanowiłem to stwierdzić doświadczalnie. Badany kompilator to GCC 2.95.3 dla MOS-a z optymalizacją -O2. Wtedy wszystkie metody zdefiniowane w ciele klasy są domyślnie traktowane jako inline. Najpierw umieszczałem w składowej 'a' liczbę, pobieraną od użytkownika przez scanf() (po to, żeby sobie kompilator nie "wyoptymalizował" całości...). Następnie jako wynik programu zwracałem tęże wartość 'a'. Zarówno odwołanie bezpośrednie do składowej, jak i poprzez metodę get() kompilator rozwija do jednej instrukcji procesora. Kod jest identyczny:

bl 00000D0C
lwz r3, 8(r1) // pobranie 'a'

Potem skomplikowałem nieco zagadnienie. Załóżmy, że dla wartości 'a' większych od 10, ma być zwrócone zero (to, o czym wspominał MDW, że chce coś tam jeszcze sprawdzić). I tutaj faktycznie GCC 2.95.3 wygenerował o jedną instrukcję więcej dla get(). Z nieznanych dla mnie powodów porównywał z liczbą 9 a następnie musiał z-OR-ować sobie flagi rejestru warunków (to ta dodatkowa instrukcja). Sięgnąłem jeszcze po GCC 4.2.1 dla MOS-a i ten już nie przejawiał takich dziwnych zachowań, otrzymany kod dla get() i bezpośredniego odwołania się do składowej (a następnie jej sprawdzenia) jest identyczny.

[#16] Re: Klasa::getA() - narzut?

@Grzegorz Kraszewski, post #15

Ooo widzisz. Dzięki wielkie! Naprawdę zawsze mnie to zagadnienie nurtowało. Naprawdę potrafi wyjść taki sam kod? Świetnie! No to już nie mam oporów przed set/get. :) Tylko będę kiedyś musiał w końcu jakoś dorzucić GCC 4 do CubicIDE. Jak sobie o tym pomyślę to mi się niedobrze robi. Zupełnie nie wiem jak mam go tam podwiesić. No ale na razie mogę robić na 2.9.3.

Dzięki wielkie za ten test. Otworzyło mi to trochę oczy. :) A tak swoją drogą to fajnie tak umieć analizować to co wypluwa kompilator. Ale to już nie moja epoka. :( Szkoda. :(

[#17] Re: Klasa::getA() - narzut?

@MDW, post #16

A tak swoją drogą to fajnie tak umieć analizować to co wypluwa kompilator. Ale to już nie moja epoka.

Muszę Cię przestrzec, że przy pisaniu krytycznych czasowo rzeczy w C++, umiejętność czytania zdisasemblowanego kodu jest bardzo potrzebna. C++ ma to do siebie, że bardzo łatwo napisać w nim kod nieefektywny, ot chociażby nieświadomie generując jakieś tymczasowe obiekty w wyrażeniu. Język C ma zaletę dosłowności, to jest kompilator zrobi dokładnie to, co mu napiszę. W C++ ceną jaką płacę za wejście na wyższy poziom abstrakcji jest większa "samodzielność" kompilatora, a wtedy z takim kompilatorem trzeba jak z małym dzieckiem - nadzorować, sprawdzać, obserwować.

A tak jeszcze na zakończenie, fajna anegdotka a propos czytania kodu spod kompilatora. Chyba już gdzieś o tym pisałem, ale wcięło mnie gdy GCC 2.95.3 dla m68k skompilował mi 'a = b + c + 2;' w... jednej instrukcji. Upchał sobie 'a' i 'b' w rejestrach adresowych i...

lea 2(a0,d0),a1

:D

[#18] Re: Klasa::getA() - narzut?

@Grzegorz Kraszewski, post #17

Pod PPC zapewne to już tak pięknie nie wyglądało...

[#19] Re: Klasa::getA() - narzut?

@MinisterQ, post #18

No niestety, tak to tylko w Erze... Pod PPC jest to prozaiczne:

add r3, r3, r0
addi r3, r3, 2

Jedyne co tu sobie kompilator ulepszył, to zauważył, że 'b' jest dalej nigdzie nieużywane, więc można zużyć ten sam rejestr na 'a'...



Ostatnia modyfikacja: 11.03.08 16:50
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem