Als Nebenfrage: Kennt jemand Tools zum automatischen Entfernen nicht verwendeter Includes?
Giorgio
Antworten:
85
Erhöht die Kompilierungszeit (möglicherweise schwerwiegendes Problem)
Verschmutzt den globalen Namespace.
Möglicher Konflikt zwischen Präprozessornamen.
Wenn nicht verwendete Header aus Bibliotheken von Drittanbietern enthalten sind, werden solche Bibliotheken möglicherweise unnötig als Abhängigkeiten verwaltet.
Potenziell ernstes Problem? Ich glaube auch, aber ich wurde ausgelacht, als ich eine Frage dazu gestellt habe. Irgendwie scheint es eine allgemein akzeptierte Meinung zu sein, dass nicht benötigte Includes kein ernstes Problem darstellen.
Giorgio
Ich nahm potenziell ernst an, weil es für einige nicht unbedingt ein ernstes Problem sein könnte. Hängt von den persönlichen Vorlieben und Prioritäten des Projektteams ab.
Mloskot
Ich habe Ihre Antwort folgendermaßen interpretiert: Nicht verwendete Includes können die Kompilierungszeit spürbar verlängern. Es kann also zu einem Problem werden und Sie müssen vorsichtig sein. Mit einer guten Disziplin können Sie nicht verwendete Includes vermeiden oder auf ein Minimum reduzieren.
Giorgio
Giorgio, ja, das ist es, was als Potenzial gemeint ist ("es kann ein Problem werden").
Mloskot
1
Insbesondere denke ich, dass dieses Problem bei großen Projekten ernst wird, wenn Hunderte oder Tausende unnötiger Header-Dateien vorhanden sind. Es kann nicht schaden, über Dinge wie Wachen oder vorkompilierte Header in dieser Antwort zu sprechen.
MWD
31
Sie erhöhen nicht unbedingt die Binärgröße, sondern die Kompilierungszeit.
Das Hauptproblem ist Unordnung . Dies sind die drei Hauptaspekte, in denen sich die Unordnung manifestiert:
Visuelle Umweltverschmutzung; während Sie versuchen, andere Includes zu finden, die Sie benötigen.
Logische Verschmutzung; Es ist wahrscheinlicher, dass es zu einer Kollision von Funktionen kommt, mehr Zeit zum Kompilieren (es kann für einige Includes sehr klein sein, aber wenn es zu einer "Richtlinie" wird, nicht benötigte Includes nicht zu bereinigen, kann dies zu einer erheblichen Hürde werden).
Abhängigkeitstrübung; Da mehr Header analysiert werden müssen, ist es schwieriger, die Abhängigkeitszyklen in Ihrem Code zu bestimmen. Es ist wichtig zu wissen, welche Abhängigkeiten in Ihrem Code bestehen, wenn Ihre Codebasis auf ein signifikantes Niveau über das Hobby-Niveau hinaus wächst.
Im Allgemeinen ja, es verursacht einige Probleme. Wenn Sie es logischerweise nicht benötigen, schließen Sie es logischerweise nicht ein.
Alle Singletons, die in einem Header als extern deklariert und in einer Quelldatei definiert sind, werden in Ihr Programm aufgenommen. Dies erhöht offensichtlich die Speichernutzung und trägt möglicherweise zu einem Leistungsaufwand bei, indem einer häufiger auf seine Auslagerungsdatei zugreift ( derzeit kein großes Problem, da Singletons normalerweise klein bis mittelgroß sind und die meisten mir bekannten Personen 6+ haben GB RAM).
Die Kompilierungszeit wird verlängert, und bei großen kommerziellen Projekten, bei denen häufig kompiliert wird, kann dies zu einem Geldverlust führen. Es kann sein, dass Ihre Gesamtzeit nur um einige Sekunden verlängert wird. Multiplizieren Sie dies jedoch mit den mehreren hundert Kompilierungen, die Sie möglicherweise testen und debuggen müssen, und Sie haben eine enorme Zeitverschwendung, die sich in einem Gewinnverlust niederschlägt.
Je mehr Header Sie haben, desto höher ist die Wahrscheinlichkeit, dass Sie eine Kollision mit einem Makro haben, das Sie in Ihrem Programm oder einem anderen Header definiert haben. Dies kann durch die korrekte Verwendung von Namespaces vermieden werden, aber es ist immer noch so mühsam zu finden. Wieder Gewinnverlust.
Trägt zum Aufblähen des Codes bei (längere Dateien und damit mehr zum Lesen) und kann die Anzahl der Ergebnisse, die Sie im Auto-Complete-Tool Ihrer IDE finden, erheblich erhöhen (einige Leute sind religiös gegen diese Tools, aber sie steigern die Produktivität in gewissem Maße).
Sie können versehentlich andere externe Bibliotheken mit Ihrem Programm verknüpfen, ohne es zu wissen.
Sie können dadurch versehentlich das Ende der Welt verursachen.
Ich gehe davon aus, dass die Header alle als "aufrichtig" angesehen werden können, das heißt, sie sind nicht genau geschrieben, um Ihren Code zu sabotieren.
Dies verlangsamt normalerweise die Kompilierung (vorkompilierte Header verringern diesen Punkt).
es impliziert Abhängigkeiten, in denen keine wirklich existieren (dies ist ein semantischer Fehler, kein tatsächlicher Fehler)
Makros verschmutzen Ihren Code (durch das Präfixieren von Makros mit namespaceähnlichen Namen, wie in BOOST_FOREACH anstelle von FOREACH).
Ein Header könnte einen Link zu einer anderen Bibliothek implizieren. In einigen Fällen kann ein nicht verwendeter Header den Linker auffordern, Ihren Code mit einer externen Bibliothek zu verknüpfen (siehe MSCVs # Pragma- Kommentar (lib, "") ). Ich glaube, ein guter Linker würde die Referenz der Bibliothek nicht behalten, wenn er nicht verwendet wird (IIRC, der Linker von MSVC wird die Referenz einer nicht verwendeten Bibliothek nicht behalten).
Ein entfernter Header ist eine Quelle weniger für unerwartete Fehler. Wenn Sie dem Header nicht vertrauen (einige Codierer sind besser als andere ...), wird durch Entfernen ein Risiko beseitigt ( Sie möchten keinen Header einfügen, der die Strukturausrichtung von allem ändert, was danach folgt: Die generierten Fehler sind ... . beleuchten ... ).
Die staticVariablendeklaration eines Headers verschmutzt Ihren Code. Jede statische Variablendeklaration führt zu einer globalen Variablen, die in Ihrer kompilierten Quelle deklariert ist.
C-Symbolnamen verschmutzen Ihren Code. Die Deklarationen im Header verschmutzen Ihren globalen oder Struktur-Namespace (und wahrscheinlich beides, da Strukturen normalerweise typisiert werden, um ihren Typ in den globalen Namespace zu bringen). Dies wird dadurch gemildert, dass Bibliotheken ihren Symbolen eine Art "Namespace-Name" voranstellen, wie SDL_CreateMutexbei SDL.
C ++ - Symbolnamen ohne Namespace verschmutzen Ihren Code. Aus den gleichen Gründen wie oben. Gleiches gilt für Header, die dieusing namespaceAnweisungfalsch verwenden. Jetzt korrigiert korrekter C ++ - Code seine Symbole. Ja, dies bedeutet, dass Sie einem C ++ - Header, der seine Symbole im globalen Namespace deklariert, normalerweise nicht vertrauen sollten ...
Ob sie die Binärgröße erhöhen oder nicht, hängt wirklich davon ab, was in ihnen enthalten ist.
Der Hauptnebeneffekt ist wahrscheinlich der negative Einfluss auf die Kompilierungsgeschwindigkeit. Wie groß die Auswirkung ist, hängt wiederum davon ab, was in ihnen enthalten ist, wie viel und ob sie andere Header enthalten.
Wenn Sie nicht sicher sind, was Sie einschließen sollen und was nicht, zeigt dies, dass der Entwickler keine Ahnung hatte, was er tat.
Include-Dateien sollen nur dann aufgenommen werden, wenn sie benötigt werden. Es mag nicht so problematisch sein, da der Arbeitsspeicher und die Geschwindigkeit des Computers heutzutage sprunghaft zunehmen, aber es war vielleicht einmal.
Wenn ein Include nicht benötigt wird, aber trotzdem enthalten ist, würde ich empfehlen, einen Kommentar daneben zu setzen, der angibt, warum Sie es aufgenommen haben. Wenn ein neuer Entwickler mit Ihrem Code fertig wird, wird er Sie sehr schätzen, wenn Sie es richtig gemacht haben.
include bedeutet, dass Sie weitere Deklarationen hinzufügen. Wenn Sie also Ihre eigene globale Funktion schreiben, müssen Sie vorsichtig sein, ob diese Funktion bereits im enthaltenen Header deklariert ist.
Ex. Wenn Sie Ihre eigene Klasse auto_ptr {} schreiben, ohne "Speicher" einzuschließen, funktioniert dies einwandfrei. Wenn Sie jedoch Speicher einschließen, gibt der Compiler einen Fehler aus, da dieser bereits in der Speicherheaderdatei deklariert wurde
Nein, wird es nicht, weil <memory>ein std :: auto_ptr deklariert wird. Dies ist der springende Punkt bei Namespaces in C ++. Ein reines C-Beispiel wäre ein besseres Beispiel ...
Paercebal
1
you are redefining class auto_ptr so it will give error: Du hast es nicht verstanden. <memory>'s auto_ptrist durch den Namespace geschützt std, sodass Sie Ihre eigene auto_ptrKlasse in den globalen Namespace oder noch besser in Ihren eigenen Namespace schreiben können. Dies würde nicht zu Konflikten führen, std::auto_ptrda Sie durch C ++ - Namespaces geschützt sind, die beide Klassen vollständig voneinander unterscheiden. Also kein Kompilierungsfehler.
Paercebal
0
Ja, sie können die Binärgröße aufgrund nicht verwendeter externer Variablen erhöhen.
//---- in unused includes ----externint/* or a big class */ unused_var;
//---- in third party library ----int unused_var = 13;
Antworten:
quelle
Sie erhöhen nicht unbedingt die Binärgröße, sondern die Kompilierungszeit.
quelle
Das Hauptproblem ist Unordnung . Dies sind die drei Hauptaspekte, in denen sich die Unordnung manifestiert:
Visuelle Umweltverschmutzung; während Sie versuchen, andere Includes zu finden, die Sie benötigen.
Logische Verschmutzung; Es ist wahrscheinlicher, dass es zu einer Kollision von Funktionen kommt, mehr Zeit zum Kompilieren (es kann für einige Includes sehr klein sein, aber wenn es zu einer "Richtlinie" wird, nicht benötigte Includes nicht zu bereinigen, kann dies zu einer erheblichen Hürde werden).
Abhängigkeitstrübung; Da mehr Header analysiert werden müssen, ist es schwieriger, die Abhängigkeitszyklen in Ihrem Code zu bestimmen. Es ist wichtig zu wissen, welche Abhängigkeiten in Ihrem Code bestehen, wenn Ihre Codebasis auf ein signifikantes Niveau über das Hobby-Niveau hinaus wächst.
quelle
Im Allgemeinen ja, es verursacht einige Probleme. Wenn Sie es logischerweise nicht benötigen, schließen Sie es logischerweise nicht ein.
Alle Singletons, die in einem Header als extern deklariert und in einer Quelldatei definiert sind, werden in Ihr Programm aufgenommen. Dies erhöht offensichtlich die Speichernutzung und trägt möglicherweise zu einem Leistungsaufwand bei, indem einer häufiger auf seine Auslagerungsdatei zugreift ( derzeit kein großes Problem, da Singletons normalerweise klein bis mittelgroß sind und die meisten mir bekannten Personen 6+ haben GB RAM).
Die Kompilierungszeit wird verlängert, und bei großen kommerziellen Projekten, bei denen häufig kompiliert wird, kann dies zu einem Geldverlust führen. Es kann sein, dass Ihre Gesamtzeit nur um einige Sekunden verlängert wird. Multiplizieren Sie dies jedoch mit den mehreren hundert Kompilierungen, die Sie möglicherweise testen und debuggen müssen, und Sie haben eine enorme Zeitverschwendung, die sich in einem Gewinnverlust niederschlägt.
Je mehr Header Sie haben, desto höher ist die Wahrscheinlichkeit, dass Sie eine Kollision mit einem Makro haben, das Sie in Ihrem Programm oder einem anderen Header definiert haben. Dies kann durch die korrekte Verwendung von Namespaces vermieden werden, aber es ist immer noch so mühsam zu finden. Wieder Gewinnverlust.
Trägt zum Aufblähen des Codes bei (längere Dateien und damit mehr zum Lesen) und kann die Anzahl der Ergebnisse, die Sie im Auto-Complete-Tool Ihrer IDE finden, erheblich erhöhen (einige Leute sind religiös gegen diese Tools, aber sie steigern die Produktivität in gewissem Maße).
Sie können versehentlich andere externe Bibliotheken mit Ihrem Programm verknüpfen, ohne es zu wissen.
Sie können dadurch versehentlich das Ende der Welt verursachen.
quelle
Ich gehe davon aus, dass die Header alle als "aufrichtig" angesehen werden können, das heißt, sie sind nicht genau geschrieben, um Ihren Code zu sabotieren.
Dies verlangsamt normalerweise die Kompilierung (vorkompilierte Header verringern diesen Punkt).
es impliziert Abhängigkeiten, in denen keine wirklich existieren (dies ist ein semantischer Fehler, kein tatsächlicher Fehler)
Makros verschmutzen Ihren Code (durch das Präfixieren von Makros mit namespaceähnlichen Namen, wie in BOOST_FOREACH anstelle von FOREACH).
Ein Header könnte einen Link zu einer anderen Bibliothek implizieren. In einigen Fällen kann ein nicht verwendeter Header den Linker auffordern, Ihren Code mit einer externen Bibliothek zu verknüpfen (siehe MSCVs # Pragma- Kommentar (lib, "") ). Ich glaube, ein guter Linker würde die Referenz der Bibliothek nicht behalten, wenn er nicht verwendet wird (IIRC, der Linker von MSVC wird die Referenz einer nicht verwendeten Bibliothek nicht behalten).
Ein entfernter Header ist eine Quelle weniger für unerwartete Fehler. Wenn Sie dem Header nicht vertrauen (einige Codierer sind besser als andere ...), wird durch Entfernen ein Risiko beseitigt ( Sie möchten keinen Header einfügen, der die Strukturausrichtung von allem ändert, was danach folgt: Die generierten Fehler sind ... . beleuchten ... ).
Die
static
Variablendeklaration eines Headers verschmutzt Ihren Code. Jede statische Variablendeklaration führt zu einer globalen Variablen, die in Ihrer kompilierten Quelle deklariert ist.C-Symbolnamen verschmutzen Ihren Code. Die Deklarationen im Header verschmutzen Ihren globalen oder Struktur-Namespace (und wahrscheinlich beides, da Strukturen normalerweise typisiert werden, um ihren Typ in den globalen Namespace zu bringen). Dies wird dadurch gemildert, dass Bibliotheken ihren Symbolen eine Art "Namespace-Name" voranstellen, wie
SDL_CreateMutex
bei SDL.C ++ - Symbolnamen ohne Namespace verschmutzen Ihren Code. Aus den gleichen Gründen wie oben. Gleiches gilt für Header, die die
using namespace
Anweisungfalsch verwenden. Jetzt korrigiert korrekter C ++ - Code seine Symbole. Ja, dies bedeutet, dass Sie einem C ++ - Header, der seine Symbole im globalen Namespace deklariert, normalerweise nicht vertrauen sollten ...quelle
Ob sie die Binärgröße erhöhen oder nicht, hängt wirklich davon ab, was in ihnen enthalten ist.
Der Hauptnebeneffekt ist wahrscheinlich der negative Einfluss auf die Kompilierungsgeschwindigkeit. Wie groß die Auswirkung ist, hängt wiederum davon ab, was in ihnen enthalten ist, wie viel und ob sie andere Header enthalten.
quelle
Zum einen verlängert man nur die Kompilierungszeit und fügt unnötige Kompilierungsabhängigkeiten hinzu .
quelle
Sie stehen für ungeschicktes Design.
Wenn Sie nicht sicher sind, was Sie einschließen sollen und was nicht, zeigt dies, dass der Entwickler keine Ahnung hatte, was er tat.
Include-Dateien sollen nur dann aufgenommen werden, wenn sie benötigt werden. Es mag nicht so problematisch sein, da der Arbeitsspeicher und die Geschwindigkeit des Computers heutzutage sprunghaft zunehmen, aber es war vielleicht einmal.
Wenn ein Include nicht benötigt wird, aber trotzdem enthalten ist, würde ich empfehlen, einen Kommentar daneben zu setzen, der angibt, warum Sie es aufgenommen haben. Wenn ein neuer Entwickler mit Ihrem Code fertig wird, wird er Sie sehr schätzen, wenn Sie es richtig gemacht haben.
quelle
include bedeutet, dass Sie weitere Deklarationen hinzufügen. Wenn Sie also Ihre eigene globale Funktion schreiben, müssen Sie vorsichtig sein, ob diese Funktion bereits im enthaltenen Header deklariert ist.
Ex. Wenn Sie Ihre eigene Klasse auto_ptr {} schreiben, ohne "Speicher" einzuschließen, funktioniert dies einwandfrei. Wenn Sie jedoch Speicher einschließen, gibt der Compiler einen Fehler aus, da dieser bereits in der Speicherheaderdatei deklariert wurde
quelle
<memory>
ein std :: auto_ptr deklariert wird. Dies ist der springende Punkt bei Namespaces in C ++. Ein reines C-Beispiel wäre ein besseres Beispiel ...you are redefining class auto_ptr so it will give error
: Du hast es nicht verstanden.<memory>
'sauto_ptr
ist durch den Namespace geschütztstd
, sodass Sie Ihre eigeneauto_ptr
Klasse in den globalen Namespace oder noch besser in Ihren eigenen Namespace schreiben können. Dies würde nicht zu Konflikten führen,std::auto_ptr
da Sie durch C ++ - Namespaces geschützt sind, die beide Klassen vollständig voneinander unterscheiden. Also kein Kompilierungsfehler.Ja, sie können die Binärgröße aufgrund nicht verwendeter externer Variablen erhöhen.
//---- in unused includes ---- extern int /* or a big class */ unused_var; //---- in third party library ---- int unused_var = 13;
quelle