In all unseren C ++ - Kursen setzen alle Lehrer immer using namespace std;
direkt nach dem #include
s in ihre .h
Dateien. Dies scheint mir seitdem gefährlich zu sein, wenn ich diesen Header in ein anderes Programm einbinde, wird der Namespace in mein Programm importiert, möglicherweise ohne es zu merken, zu beabsichtigen oder zu wollen (die Aufnahme von Headern kann sehr tief verschachtelt sein).
Meine Frage ist also doppelt: Habe ich Recht, dass using namespace
sie nicht in Header-Dateien verwendet werden sollte, und / oder gibt es eine Möglichkeit, sie rückgängig zu machen, etwa:
//header.h
using namespace std {
.
.
.
}
Noch eine Frage in die gleiche Richtung: Sollte eine Header-Datei #include
alle Header enthalten, die die entsprechende .cpp
Datei benötigt, nur diejenigen, die für die Header-Definitionen benötigt werden, und die .cpp
Datei #include
den Rest oder keine lassen und alles deklarieren, was sie benötigt extern
?
Die Argumentation hinter der Frage ist dieselbe wie oben: Ich möchte keine Überraschungen beim Einfügen von .h
Dateien.
Wenn ich recht habe, ist das auch ein häufiger Fehler? Ich meine in der realen Programmierung und in "echten" Projekten da draußen.
Danke dir.
quelle
using namespace
Anweisungen Namenskollisionen erhalten, können Sie den vollständig qualifizierten Namen verwenden, um das Problem zu lösen.Antworten:
Sie sollten definitiv NICHT
using namespace
in Headern verwenden, genau aus dem Grund, den Sie sagen, dass dies die Bedeutung von Code in anderen Dateien, die diesen Header enthalten, unerwartet ändern kann. Es gibt keine Möglichkeit, einen rückgängig zu machen,using namespace
was ein weiterer Grund ist, warum er so gefährlich ist. Normalerweise verwende ich nurgrep
oder ähnliches, um sicherzustellen, dass diesusing namespace
nicht in Kopfzeilen aufgerufen wird, anstatt etwas Komplizierteres auszuprobieren. Wahrscheinlich kennzeichnen dies auch statische Codeprüfer.Der Header sollte nur die Header enthalten, die zum Kompilieren benötigt werden. Eine einfache Möglichkeit, dies durchzusetzen, besteht darin, vor allen anderen Headern immer zuerst den eigenen Header jeder Quelldatei einzuschließen. Dann kann die Quelldatei nicht kompiliert werden, wenn der Header nicht in sich geschlossen ist. In einigen Fällen, z. B. in Bezug auf Implementierungsdetailklassen innerhalb einer Bibliothek, können Sie Forward-Deklarationen verwenden, anstatt
#include
die volle Kontrolle über die Definition einer solchen Forward-Deklarationsklasse zu haben.Ich bin mir nicht sicher, ob ich es allgemein nennen würde, aber es taucht definitiv ab und zu auf, normalerweise geschrieben von neuen Programmierern, die sich der negativen Konsequenzen nicht bewusst sind. In der Regel werden Probleme nur durch ein wenig Aufklärung über die Risiken behoben, da sie relativ einfach zu beheben sind.
quelle
using
Anweisungen in unseren.cpp
Dateien verwenden? Die3rdPartyLib::BigClassName<3rdPartyLib::AnotherBigName,3rdPartyLib::AnotherBigName>::Iterator
s sind der Tod bis in die Fingerspitzen.template
Funktionen rationalisieren - die in den Headern sein sollen?typedefs
?using
Anweisungen in.cpp
Dateien ohne große Bedenken verwenden, da der Bereich nur auf diese Datei beschränkt ist, dies jedoch niemals vor einer#include
Anweisung. Was die in Headern definierten Vorlagenfunktionen betrifft, kenne ich leider keine andere gute Lösung als nur das Schreiben des Namespace ... Vielleicht könnten Sie eineusing
Deklaration in einen separaten Bereich einfügen{ /* using statement in between brackets */ }
, der zumindest verhindern würde, dass sie aus der aktuellen Datei entweicht .Punkt 59 in Sutters und Alexandrescus "C ++ Coding Standards: 101 Regeln, Richtlinien und Best Practices" :
Eine Header-Datei ist ein Gast in einer oder mehreren Quelldateien. Eine Header-Datei, die
using
Direktiven und Deklarationen enthält, bringt auch ihre Rowdy Buddies rüber.Eine
using
Erklärung bringt einen Kumpel herein. Eineusing
Direktive bringt alle Buddies in den Namespace. Die Verwendung durch Ihre Lehrerusing namespace std;
ist eine Verwendungsrichtlinie.Im Ernst, wir haben Namespaces, um Namenskonflikte zu vermeiden. Eine Header-Datei soll eine Schnittstelle bereitstellen. Die meisten Header sind unabhängig davon, welcher Code sie jetzt oder in Zukunft enthalten kann. Durch Hinzufügen von
using
Anweisungen zur internen Bequemlichkeit innerhalb des Headers werden diese praktischen Namen allen potenziellen Clients dieses Headers hinzugefügt. Das kann zu Namenskonflikten führen. Und es ist einfach unhöflich.quelle
Sie müssen vorsichtig sein, wenn Sie Header in Header einfügen. In großen Projekten kann eine sehr verwickelte Abhängigkeitskette erstellt werden, die größere / längere Neuerstellungen auslöst, als tatsächlich erforderlich waren. In diesem Artikel und seinen Folgemaßnahmen erfahren Sie mehr über die Bedeutung einer guten physischen Struktur in C ++ - Projekten.
Sie sollten Header nur dann in einen Header einfügen, wenn dies unbedingt erforderlich ist (wenn die vollständige Definition einer Klasse erforderlich ist) und die Vorwärtsdeklaration verwenden, wo immer Sie können (wenn die Klasse erforderlich ist, handelt es sich um einen Zeiger oder eine Referenz).
Bei Namespaces verwende ich normalerweise den expliziten Namespace-Bereich in meinen Header-Dateien und
using namespace
füge nur einen in meine CPP-Dateien ein.quelle
template
Funktionsdeklaration? das muss im header vorkommen, nein?Lesen Sie die Codierungsstandards für das Goddard Space Flight Center (für C und C ++). Das stellt sich als etwas schwieriger heraus als früher - siehe die aktualisierten Antworten auf die SO-Fragen:
Der GSFC C ++ - Codierungsstandard lautet:
Die erste der Fragen, auf die verwiesen wird, enthält jetzt ein Zitat aus dem GSFC C-Codierungsstandard und die Begründung, aber die Substanz ist am Ende dieselbe.
quelle
Sie haben Recht, dass
using namespace
im Header gefährlich ist. Ich weiß nicht, wie ich es rückgängig machen soll. Es ist leicht zu erkennen, aber suchen Sie einfachusing namespace
in den Header-Dateien. Aus diesem letzten Grund ist es in realen Projekten ungewöhnlich. Erfahrene Mitarbeiter werden sich bald beschweren, wenn jemand so etwas tut.In realen Projekten wird versucht, die Anzahl der enthaltenen Dateien zu minimieren. Je weniger Sie einschließen, desto schneller wird die Kompilierung durchgeführt. Das spart allen Zeit. Wenn die Header-Datei jedoch davon ausgeht, dass etwas davor enthalten sein sollte, sollte sie es selbst enthalten. Andernfalls sind die Header nicht in sich geschlossen.
quelle
Du hast recht. Und jede Datei sollte nur die Header enthalten, die von dieser Datei benötigt werden. Was "Ist es in Projekten der realen Welt üblich, Dinge falsch zu machen?" - Oh ja!
quelle
Wie alle Dinge in der Programmierung sollte Pragmatismus den Dogmatismus, IMO, für sich gewinnen.
Solange Sie die Entscheidung projektweit treffen ("Unser Projekt verwendet STL ausgiebig und wir möchten nicht alles mit std :: voranstellen müssen"), sehe ich das Problem damit nicht. Das einzige, was Sie riskieren, sind schließlich Namenskollisionen, und angesichts der Allgegenwart von STL ist es unwahrscheinlich, dass dies ein Problem darstellt.
Wenn es sich jedoch um eine Entscheidung eines Entwicklers in einer einzelnen (nicht privaten) Header-Datei handelt, kann ich sehen, wie dies zu Verwirrung im Team führen würde und vermieden werden sollte.
quelle
In Bezug auf "Gibt es eine Möglichkeit, [eine
using
Erklärung] rückgängig zu machen ?"Ich halte es für nützlich, darauf hinzuweisen, dass
using
Erklärungen vom Geltungsbereich betroffen sind.Also effektiv ja. Durch die Einschränkung des Geltungsbereichs der
using
Erklärung bleibt ihre Wirkung nur in diesem Geltungsbereich bestehen. Es wird rückgängig gemacht, wenn dieser Bereich endet.Wenn die
using
Deklaration in einer Datei außerhalb eines anderen Bereichs deklariert wird, hat sie einen Dateibereich und wirkt sich auf alles in dieser Datei aus.Wenn sich die
using
Deklaration im Fall einer Header-Datei im Dateibereich befindet, erstreckt sich dies auf den Bereich jeder Datei, in der der Header enthalten ist.quelle
namespace
Deklarationsmaterial) und wie er tatsächlich funktioniert (wie eine Variable).{}
Wenn Sie es einschließen, schränken Sie seinen Umfang ein,{}
nachdem Sie nichts damit zu tun haben. Das ist eine zufällige Art und Weise, wie dasusing namespace
global angewendet wird.Ich glaube, Sie können 'using' in C ++ - Headern sicher verwenden, wenn Sie Ihre Deklarationen in einen verschachtelten Namespace wie folgt schreiben:
Dies sollte nur die in 'DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED' deklarierten Dinge ohne die verwendeten Namespaces enthalten. Ich habe es auf mingw64 Compiler getestet.
quelle
using
Deklarationen in Funktionsdefinitionen einzufügen, wo ich kann, damit sie Namespaces außerhalb der Funktion nicht verschmutzen. Aber jetzt möchte ich benutzerdefinierte C ++ 11-Literale in einer Header-Datei verwenden, und gemäß der üblichen Konvention sind die Literaloperatoren durch einen Namespace geschützt. Ich möchte sie jedoch nicht in Konstruktorinitialisiererlisten verwenden, die nicht in einem Bereich liegen, in dem ich eine umweltfreundlicheusing
Deklaration verwenden kann. Das ist also großartig, um dieses Problem zu lösen.error: ... DECLARATIONS_WITH_NAMESPACES_USED_INCLUDED:: DECLARATIONS_WITH_NO_NAMESPACES_USED_INCLUDED::ClassName ...
. Zumindest passiert das für mich in g ++.