Dlaczego polimorfizm dynamiczny jest kosztowny?

0

Hej
Dlaczego uważa się, że polimorfizm dynamiczny jest kosztowny w przeciwieństwie do statycznego, bo wydaje mi się, że powód numer 2 to tylko w jakichśtam granicznych i rzadkich przypadkach a pierwszy to można olać, nie jest aż tak kosztowny?
1.) wywołanie metody wirtualnej powoduje, że trzeba jeszcze odwołać się do vtable i to tyle czasu aż zabiera, ze 2-3 instrukcje procesora więcej?
2.) bo trzeba dynamicznie rzutować jak ktoś nie jest pewny rzutowania, np.

class Base
{
public:
   virtual ~Base() = default;
   //jakieś metody wirtualne
};
class Derived: public Base
{
   void fun(){} //dodatkowa metoda ktorej nie ma w Base
}

ktoś ma wskaźnik do klasy bazowej pod którym rpzechowuje obiekt Derived a chce wywołać metodę fun, no to musi rzutować i jak nie jest pewny w swoim programie czy to jest właściwe to musi rzutować przez dynamic_cast zamiast static_cast i to jest kosztowne plus if na dynamiczne sprawdzenie typu czy nie jest NULLem.

Jeszcze na korzyść używania polimorfizmu statycznego znalazłem argument, że w czasie kompilacji jest sprawdzanie typów a przy polimorfiźmie dynamicznym w czasie kompilacji. Ale to też ktoś na wyrost napisał, bo to tylko tyczy się powyższego przypadku numer 2, gdy ktoś dynamic_cast używa, mam rację?

Czy są jeszcze jakieś powody?
I jeszcze dobre pytanie czy mamy do czynienia z polimorfizmem dla powyższego przykładu jeżeli od razu podamy typ zmiennej Derived? To wtedy mamy statyczny polimorfizm? A więc do statycznego polimorfizmu nie zaliczają się tylko templejty ale też przypadki "dynamicznego polimorfizmu" w ktorych od razu jest podany typ pochodny?

1

Mając dynamiczne wywołenie kompilator za bardzo tego nie zoptymalizuje, musi znać poznać typ obiektu, by wiedzieć jaka metoda zostanie wywołana. W ten sposób tracisz korzyść jaka wynika ze stosowania funkcji inline.

2

Dlaczego uważa się, że polimorfizm dynamiczny jest kosztowny

Polimorficzne wywołanie z użyciem typu interfejsu to niemal gwarantowany "cache miss". Każdy potomek zazwyczaj potrzebuje innej ilości pamięci, a nie wiadomo aż do samego wywołania jaki typ będzie przekazany i ile będzie potrzeba tejże pamięci. To taki odpowiedni void pointer z C w C++. Dodatkowo vtable rozwala alignemnt klasy, co również nie jest przyjazne dla cache, ale to jest ciut mniejszy problem.

0

Dodam jeszcze dwa istotne powody:

  1. Do funkcji wirtualnych nie może zostać zastosowany mechanizm inline, co w przypadku "małych" funkcji może być kosztowne.
  2. Każde wywołanie funkcji wirtualnych jest obarczone dodatkową operacją polegającą na dodaniu do wskaźnika "na" vftable odpowiedniego offsetu odpowiadającego danej funkcji (tzw. pointer dereference).

Tutaj można znaleźć ciekawy artykuł na ten temat.

1
several napisał(a):

Dodatkowo vtable rozwala alignemnt klasy

Niby w jaki sposób?

5

Bo ludzie, wolą gadać o wydajności zamiast ją mierzyć.
Wolą winić polimorfizm, niż zrobić profilowanie kodu i ustalać wąskie gardło aplikacji.
Bo kiedyś faktycznie był to problem.

Tak polimorfizm daje narzut na wydajność.
Tak jest wiele przykładów, gdzie wyeliminowanie polimorfizmu znacznie poprawia wydajność aplikacji.
Jednak bez weryfikacji (pomiarów, profilowania), jest to zwykle tylko kozioł ofiarny.

0
Azarien napisał(a):
several napisał(a):

Dodatkowo vtable rozwala alignemnt klasy

Niby w jaki sposób?

@Azarien Chyba zastosowałem zbyt duży skrót myślowy. Każda instancja obiektu jest powiększona o rozmiar pointera do vtable, zazwyczaj jest to osiem bajtów, ale nie zawsze. Ta zmienna plus padding sprawia, że trudniej planować czy nasz typ zmieści się w rekordzie cache czy nie, trudniej też kontrolować sam padding. Tak jak napisałem, w praktyce zazwczyaj jest to mniejszy problem bo w praktyce przechowuje się w strukturach trochę więcej danych i procentowy narzut wynikający z przechowywania dodatkowego pointera jest mały.

W przykładzie poniżej typ bez wirtualnej metody potrzebuje 4 bajty, dodanie virtual do metody powiększyło rozmiar do 16.
https://wandbox.org/permlink/ucN7stIjOfnmVG43

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