Założenia
Jedną z zalet bibliotek tylko nagłówkowych dla C ++ jest to, że nie trzeba ich oddzielnie kompilować.
W C i C ++
inline
ma sens tylko wtedy, gdy funkcja jest zdefiniowana w pliku nagłówkowym *.Tradycyjnie w C używany jest układ .c / .h, w którym nagłówek reprezentuje minimalny publiczny interfejs jednostki tłumaczeniowej. Podobnie .cpp / hpp.
Pytanie
Czy biblioteki zawierające tylko nagłówki są generalnie bardziej wydajne pod względem kodu i czasu wykonania niż tradycyjny układ? Jeśli tak, to czy wynika to z dużej inlinizacji lub innych optymalizacji?
* - zdefiniowanie funkcji w nagłówku pozwala kompilatorowi zobaczyć implementację podczas kompilacji dowolnej jednostki tłumaczeniowej i praktycznie umożliwia wstawienie kodu
Odpowiedzi:
Nie, to nie jest zaleta, wręcz przeciwnie - główna część biblioteki musi być kompilowana tak często, jak się ją włącza, nie tylko raz. Zwykle wydłuży to czas kompilacji. Jeśli jednak masz na myśli zalety wymienione tutaj w Wikipedii : ten artykuł mówi o zmniejszonym obciążeniu administracyjnym dotyczącym całego procesu kompilacji, pakowania i wdrażania.
Zależy to od systemu kompilatora / linkera, ale wydaje mi się, że w przypadku większości istniejących kompilatorów C i C ++ jest to prawda.
To jest w większości poprawne. Nagłówki klasy C ++ często zawierają więcej niż minimalny publiczny interfejs - zazwyczaj zawierają również wiele prywatnych rzeczy. Aby to złagodzić, stosuje się takie rzeczy, jak idiom PIMPL . Jest to coś w rodzaju „przeciwieństwa” biblioteki tylko nagłówkowej, stara się zminimalizować niezbędną zawartość nagłówka.
Ale aby odpowiedzieć na twoje główne pytanie: jest to kompromis. Im więcej kodu biblioteki umieszcza się w plikach nagłówkowych, tym bardziej kompilator ma szansę zoptymalizować kod pod kątem szybkości (jeśli tak się naprawdę zdarza lub jeśli wzrost jest zauważalny, to zupełnie inne pytanie). Z drugiej strony, zbyt dużo kodu w nagłówkach wydłuża czas kompilacji. Szczególnie w dużych projektach C ++ może to stać się poważnym problemem, patrz „Projektowanie oprogramowania w dużej skali C ++” Johna Lakosa - choć książka jest nieco przestarzała, a niektóre z opisanych tam problemów są rozwiązywane przez nowoczesne kompilatory, ogólne pomysły / rozwiązania są nadal aktualne.
W szczególności, gdy nie używasz stabilnej biblioteki (strony trzeciej), ale opracowujesz własne biblioteki lib podczas projektu, czasy kompilacji stają się widoczne. Za każdym razem, gdy zmieniasz coś w bibliotece, musisz zmienić plik nagłówka, co spowoduje rekompilację i powiązanie wszystkich jednostek zależnych.
IMHO popularność bibliotek tylko nagłówkowych jest spowodowana popularnością szablonów meta-programowania. W przypadku większości kompilatorów biblioteki szablonów muszą być tylko nagłówkami, ponieważ kompilator może uruchomić główny proces kompilacji tylko wtedy, gdy podano parametry typu, a dla pełnej kompilacji i optymalizacji kompilator musi widzieć „oba naraz” - kod biblioteki plus szablon wartości parametrów. Uniemożliwia to (lub przynajmniej utrudnia) tworzenie jakichkolwiek „wstępnie skompilowanych” jednostek kompilacji dla takiej biblioteki.
źródło
Cóż, najpierw zburzymy niektóre z twoich założeń:
Kompilowanie osobno oznacza potencjalnie brak konieczności ponownej kompilacji wszystkiego, jeśli zmieni się tylko część.
Zatem wada zamiast przewagi.
Tak, jedynym efektem,
inline
jaki pozostał, jest wyjątek od reguły jednej definicji .Biada wam, jeśli te definicje różnią się w jakikolwiek sposób.
Tak więc, jeśli funkcja jest wewnętrzną jednostką kompilacji, zaznacz ją
static
. To sprawia, że wstawianie jest bardziej prawdopodobne, ponieważ funkcja musi być dostępna w celu jej wstawienia.Mimo to spójrz na optymalizację czasu łącza, obsługiwaną co najmniej przez MSVC ++, gcc i clang.
Cóż, tylko przedstawienie minimalnego interfejsu jest z pewnością jednym z celów, aby osiągnąć wyższą stabilność API i ABI oraz zminimalizować czas kompilacji.
Zwłaszcza klasy C ++ nie są do tego specjalnie dostosowane, ponieważ wszystkie prywatne bity przeciekają do nagłówka, podobnie jak chronione, czy chcesz z nich czerpać, czy nie.
Wzorzec projektowy PIMPL służy do zmniejszenia takich szczegółów.
Jednak częścią, w której interfejs i implementacja całkowicie nie działają w C ++, są szablony.
Komitet próbował zrobić coś z wyeksportowanymi szablonami , ale zostało to porzucone jako zbyt skomplikowane i tak naprawdę nie działające.
Teraz pracują nad odpowiednim systemem modułów , choć działa powoli. To znacznie skraca czas kompilacji, a także powinno zwiększyć stabilność API i ABI poprzez zmniejszenie ich powierzchni.
Biblioteki zawierające tylko nagłówki mogą być bardziej wydajne pod względem rozmiaru kodu i czasu wykonywania, choć zależy to od tego, czy biblioteka jest współużytkowana, ile z niej jest wykorzystywana, w jaki sposób i czy inlining stanowi decydującą wygraną w tym konkretnym przypadku.
Powodem, dla którego wstawianie jest tak ważne dla optymalizacji, nie jest to, że wkładanie samo w sobie jest tak świetnym wzmocnieniem, ale ze względu na możliwości ciągłej propagacji i dalszej optymalizacji, otwiera się.
źródło