Kilka powodów
Pliki nagłówkowe
Każda jednostka kompilacji wymaga (1) załadowania i (2) skompilowania setek, a nawet tysięcy nagłówków. Każdy z nich zazwyczaj musi zostać ponownie skompilowany dla każdej jednostki kompilacji, ponieważ preprocesor zapewnia, że wynik kompilacji nagłówka może się różnić między każdą jednostką kompilacji. (Makro może być zdefiniowane w jednej jednostce kompilacji, która zmienia zawartość nagłówka).
Jest to prawdopodobnie Głównym powodem, ponieważ wymaga ogromnych ilości kodu zostać skompilowane dla każdej jednostki kompilacji, a dodatkowo, każdy nagłówek musi być skompilowany wiele razy (raz dla każdej jednostki kompilacji, która zawiera go).
Łączenie
Po skompilowaniu wszystkie pliki obiektowe muszą zostać połączone. Zasadniczo jest to monolityczny proces, którego nie da się zrównoważyć, i musi on przetworzyć cały projekt.
Rozbiór gramatyczny zdania
Składnia jest wyjątkowo skomplikowana do przeanalizowania, zależy w dużym stopniu od kontekstu i bardzo trudno jest ją jednoznacznie określić. To zajmuje dużo czasu.
Szablony
W języku C # List<T>
jest to jedyny typ, który jest kompilowany, bez względu na to, ile wystąpień listy masz w swoim programie. W C ++ vector<int>
jest całkowicie odrębnym typem vector<float>
i każdy będzie musiał zostać skompilowany osobno.
Dodaj do tego, że szablony tworzą pełny „podjęzyk” Turinga, który kompilator musi interpretować, a to może stać się absurdalnie skomplikowane. Nawet stosunkowo prosty kod metaprogramowania szablonów może definiować szablony rekurencyjne, które tworzą dziesiątki instancji szablonów. Szablony mogą również skutkować wyjątkowo złożonymi typami, z absurdalnie długimi nazwami, co dodaje dodatkowej pracy do linkera. (Musi porównać wiele nazw symboli, a jeśli nazwy te mogą urosnąć do wielu tysięcy znaków, mogą stać się dość drogie).
I oczywiście zaostrzają problemy z plikami nagłówkowymi, ponieważ szablony zwykle muszą być definiowane w nagłówkach, co oznacza, że o wiele więcej kodu musi zostać przeanalizowane i skompilowane dla każdej jednostki kompilacji. W zwykłym kodzie C nagłówek zazwyczaj zawiera tylko deklaracje przesyłania, ale bardzo mało rzeczywistego kodu. W C ++ nierzadko prawie cały kod znajduje się w plikach nagłówkowych.
Optymalizacja
C ++ pozwala na bardzo dramatyczne optymalizacje. C # lub Java nie pozwalają na całkowite wyeliminowanie klas (muszą one tam być w celu odbicia), ale nawet prosty metaprogram szablonu C ++ może z łatwością wygenerować dziesiątki lub setki klas, z których wszystkie są uwzględniane i ponownie eliminowane podczas optymalizacji faza.
Ponadto kompilator musi w pełni zoptymalizować program C ++. Program AC # może polegać na kompilatorze JIT w celu wykonywania dodatkowych optymalizacji w czasie ładowania, C ++ nie ma takich „drugich szans”. To, co generuje kompilator, jest tak zoptymalizowane, jak to tylko możliwe.
Maszyna
C ++ jest kompilowany do kodu maszynowego, który może być nieco bardziej skomplikowany niż użycie kodu bajtowego Java lub .NET (szczególnie w przypadku x86). (Jest to wspomniane kompletnie tylko dlatego, że zostało wspomniane w komentarzach itp. W praktyce jest mało prawdopodobne, aby krok ten zajął więcej niż niewielką część całkowitego czasu kompilacji).
Wniosek
Większość tych czynników jest współdzielona przez kod C, który faktycznie kompiluje się dość skutecznie. Etap analizy jest w C ++ o wiele bardziej skomplikowany i może zająć znacznie więcej czasu, ale głównym przestępcą są prawdopodobnie szablony. Są użyteczne i sprawiają, że C ++ jest znacznie potężniejszym językiem, ale także odbijają się na szybkości kompilacji.