2015-05-05 11 views
23

Widziałem kilka pytań dotyczących wykrywania niepotrzebnych plików #include w projekcie C++. To pytanie często mnie intrygowało, ale nigdy nie znalazłem satysfakcjonującej odpowiedzi.Czy niepotrzebne są dodatkowe pliki narzutów?

Jeśli są jakieś pliki nagłówkowe, które nie są używane w projekcie C++, czy to obciążenie? Rozumiem, że oznacza to, że przed kompilacją zawartość wszystkich plików nagłówkowych zostałaby skopiowana do dołączonych plików źródłowych, co spowodowałoby niepotrzebną kompilację.

Jak daleko rozlewa się ten rodzaj nakładów na skompilowane pliki obiektów i pliki binarne?

kompilatory nie są w stanie wykonać pewne optymalizacje, aby upewnić się, że ten rodzaj narzutu nie są przesyłane do otrzymanych plików obiektowych i plików binarnych?

Biorąc pod uwagę fakt, że prawdopodobnie nie wiem nic o optymalizacji kompilatora, nadal chcę o to zapytać, na wypadek, gdyby istniała odpowiedź.

Jako programista, który wykorzystuje szeroką gamę C++ bibliotek dla jego pracy, jaki rodzaj praktyk programowania powinien śledzę zachować unikając takich kosztów ogólnych? Czy dokładne zapoznanie się z każdą biblioteką działa w jedyny sposób?

+0

To zależy od zawartości plików dołączanych. Deklaracje struktury nie powodują żadnych narzutów środowiska wykonawczego. Zewnętrzne deklaracje zmiennych do. – Barmar

+0

Zależności boczne na bok, niepotrzebne obejmują wydłużają czas kompilacji, co w przypadku dużych projektów już zajmuje dużo czasu (rząd wielkości - godzin) – CoryKramer

+0

@Cyber ​​Jeśli zajmuje to już godziny, kolejne 30 sekund tutaj lub nie ma zamiaru duża różnica. – Barmar

Odpowiedz

3

Oczywiście każdy koszt #include jest narzutem. Kompilator musi przeanalizować ten plik.

więc ich unikać. Użyj deklaracji forward tam, gdzie to możliwe.

Przyspiesza kompilację. Zobacz Scott Myers książkę na ten temat

+7

Podejrzewam, że jest on głównie zainteresowany obciążeniem runtime. – Barmar

23

To nie wpływa na wydajność binarny lub nawet zawartości pliku binarnego, dla prawie wszystkich nagłówków. Deklaracje nie generuje kod w ogóle, definicje inline/static/anonymous-namespace są zoptymalizowane dalej, jeśli nie są one wykorzystywane, a nie nagłówek powinien zawierać widocznych zewnętrznie definicji (który łamie jeśli nagłówek jest zawarty przez więcej niż jedną jednostkę tłumaczenie) .

As @ T.C. zwraca uwagę, że wyjątek stanowią widoczne wewnątrz obiekty statyczne z nietrywialnymi konstruktorami. iostream robi to, na przykład. Program musi zachowywać się tak, jakby wywoływano konstruktora, a kompilator zwykle nie ma wystarczających informacji, aby zoptymalizować konstruktora.

Ma jednak wpływ na to, jak długo trwa kompilacja i ile plików zostanie skompilowanych po zmianie nagłówka. W przypadku dużych projektów jest to wystarczająca zachęta do dbałości o niepotrzebne załączniki.

+0

Istnieje kilka wyjątków. Definicje funkcji w nagłówkach są duplikowane w każdym binarnym pliku wynikowym, który je zawiera, a większe pliki binarne ładują się dłużej, a zduplikowane funkcje zakłócają pamięć podręczną instrukcji, co skutkuje minimalnymi karami wydajności. –

+0

@MooingDuck Linker zwykle może je wyrzucić, nie? –

+0

@ T.C .: Wyrzuca duplikaty funkcji _in plików obiektów, ponieważ są one połączone w jeden plik binarny_. Nie może jednak wyrzucać funkcji używanych w kilku bibliotekach DLL lub EXE. –

1

Prosta odpowiedź brzmi tak, to narzut miarę kompilacja jest zaniepokojony, ale na starcie jest jedynie zamiar stworzyć żadnej różnicy. Powód: powiedzmy, że dodajesz #include <iostream> (tylko na przykład) i zakładasz, że nie używasz żadnej z jego funkcji, wtedy g ++ 4.5.2 ma jakieś dodatkowe 18.560 linii kodu do przetworzenia (kompilacja). Ale jeśli chodzi o narzut wykonawczego dotyczy Nie sądzę, że to stwarza problem z wydajnością.

Można również zapoznać Are unused includes harmful in C/C++? gdzie bardzo lubiłem ten punkt wykonane przez Davida Younga

Wszelkie singletons zadeklarowany jako zewnętrzny w nagłówku i zdefiniowany w pliku źródłowym będą zawarte w programie. To oczywiście zwiększa zużycie pamięci i może przyczynić się do zwiększenia wydajności o , powodując, że ktoś uzyskuje dostęp do swoich plików stronicowych częściej (obecnie niewiele z problemu , ponieważ pojedyncze egzemplarze są zwykle małe do średnich rozmiarów i , ponieważ większość ludzi wiem, że masz 6 GB pamięci RAM).

+0

Zabawne użyłeś "#include " jako przykładu, ponieważ włączenie tego nagłówka powoduje mały nakład w czasie wykonywania. –

+0

@ T.C:: - Rzeczywiście, ale ja tylko próbowałem coś wyjaśnić. Być może mógłbym dodać '#include ', który ma około 74k wierszy. –

4

Poza oczywiście dłuższymi czasami kompilacji, mogą występować inne problemy. Najważniejszą z nich jest zależność od zewnętrznych bibliotek. Nie chcesz, aby twój program był zależny od większej ilości bibliotek, niż to konieczne.

Następnie należy zainstalować te biblioteki w każdym systemie, na którym program ma działać. Może to stać się koszmarem, zwłaszcza gdy następny programista musi zainstalować pewną bibliotekę klienta bazy danych, chociaż program nigdy nie korzysta z bazy danych.

Ponadto, szczególnie nagłówki bibliotek często mają tendencję do definiowania makr. Czasami te makra mają bardzo ogólne nazwy, które złamią ci kod lub które są niezgodne z innymi nagłówkami bibliotek, których możesz potrzebować.

+0

Czy naprawdę możesz mieć * zależność * od zewnętrznej biblioteki, jeśli w rzeczywistości niczego nie używasz? Na przykład, jeśli "# include" to, ale nigdy nie odwołuje się do żadnej z jego zawartości? –

+0

@ Mr.Llama Prawdopodobnie myślisz o linkerze wyrzucającym wszystko, a nawet zmuszającym do połączenia z rzeczywistą biblioteką. Ale musisz zainstalować bibliotekę, aby znaleźć nagłówek, w przeciwnym razie twój kod się nie skompiluje. Z prawnego punktu widzenia może on już być liczony jako licencja zależna. Więc już jesteś zależny od biblioteki, nawet jeśli chcesz zbudować swój projekt. –

Powiązane problemy