Es scheint unterschiedliche Ansichten zur Verwendung von 'using' in Bezug auf den Standard-Namespace zu geben.
Einige sagen "benutze" using namespace std
, andere sagen "nicht", sondern stellen std-Funktionen voran, die mit " std::
" verwendet werden sollen, während andere sagen, benutze so etwas:
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::vector;
für alle Standardfunktionen, die verwendet werden sollen.
Was sind die Vor- und Nachteile von jedem?
c++
namespaces
paoloricardo
quelle
quelle
Antworten:
Die meisten C ++ Benutzer sind sehr glücklich , Lesen
std::string
,std::vector
etc. In der Tat, ein rohes zu sehenvector
macht mich fragen , ob dies das iststd::vector
oder ein anderer benutzerdefiniertvector
.Ich bin immer gegen die Verwendung
using namespace std;
. Es importiert alle Arten von Namen in den globalen Namespace und kann alle möglichen nicht offensichtlichen Mehrdeutigkeiten verursachen.Hier sind einige gebräuchliche Bezeichner, die sich im
std
Namespace befinden: count, sort, find, same, reverse. Nachdem eine lokale Variable namenscount
Mittel , dieusing namespace std
nicht ermöglichen wird , den Sie verwendencount
stattstd::count
.Das klassische Beispiel für einen unerwünschten Namenskonflikt lautet wie folgt. Stellen Sie sich vor, Sie sind Anfänger und wissen nichts darüber
std::count
. Stellen Sie sich vor, Sie verwenden entweder etwas anderes<algorithm>
oder es wurde von einem scheinbar nicht verwandten Header eingezogen.Der Fehler ist normalerweise lang und unfreundlich, da
std::count
es sich um eine Vorlage mit einigen langen verschachtelten Typen handelt.Dies ist jedoch in Ordnung, da es
std::count
in den globalen Namespace geht und die Funktionsanzahl ihn verbirgt.Vielleicht etwas überraschend, das ist OK. In einen deklarativen Bereich importierte Bezeichner werden im gemeinsamen Namespace angezeigt, der sowohl den Ort enthält, an dem sie definiert sind, als auch den Ort, an den sie importiert werden. Mit anderen Worten,
std::count
ist sichtbar wiecount
im globalen Namespace, jedoch nur innerhalbincrement
.Und aus ähnlichen Gründen
count
ist hier nicht eindeutig.using namespace std
nicht verursachenstd::count
, verstecken Sie das Äußere,count
wie es zu erwarten war. Dieusing namespace
Regel bedeutet, dass siestd::count
(in derincrement
Funktion) so aussieht, als ob sie im globalen Bereich deklariert wurde, dh im selben Bereich wieint count = 0;
und damit die Mehrdeutigkeit verursacht.quelle
using std::xxx;
. Es verschmutzt keinen Namespace, das Schreiben von Code wird kürzer und ich denke, escopy
ist viel lesbarer alsstd::copy
.Ausschluss der Grundlagen (Sie müssen std :: vor allen stl-Objekten / -Funktionen hinzufügen und haben weniger Konfliktwahrscheinlichkeit, wenn Sie nicht den Namespace std verwenden).
Es ist auch erwähnenswert, dass Sie nie setzen sollten
In einer Header-Datei, da sie an alle Dateien weitergegeben werden kann, die diese Header-Datei enthalten, auch wenn sie diesen Namespace nicht verwenden möchten.
In einigen Fällen ist es sehr vorteilhaft, Dinge wie zu verwenden
Als ob es eine spezielle Version von Swap gibt, wird der Compiler diese verwenden, andernfalls wird darauf zurückgegriffen
std::swap
.Wenn Sie anrufen
std::swap
, verwenden Sie immer die Basisversion, die die optimierte Version nicht aufruft (falls vorhanden).quelle
using std::swap
(was das einzige ist, was ich jemals benutze).u n s
sich ausbreiten kann. Nur um zu beachten, dass es sich auch in korrekt konstruierte Header einschleichen kann: Sie müssen nur nach einem Rogue-Header eingefügt werden.swap
odermove
(oderhash
,less
etc.) Spezialisierung, sollten Sie diese Spezialisierung in sein Puttingnamespace std
sowieso. Zum Beispiel:namespace std {template<> class hash<X> {public: size_t operator()(const X&) const};} class X: {friend size_t std::hash<X>::operator()(const X&)};
Zunächst einige Begriffe:
using std::vector;
using namespace std;
Ich denke, dass die Verwendung von using-Direktiven in Ordnung ist, solange sie nicht im globalen Bereich einer Header-Datei verwendet werden. Also haben
in Ihrer CPP-Datei ist kein wirkliches Problem, und wenn sich herausstellt, dass es vollständig unter Ihrer Kontrolle steht (und es kann auf Wunsch sogar auf bestimmte Blöcke beschränkt werden). Ich sehe keinen besonderen Grund, den Code mit einer Menge zu überladen
std::
Qualifikationsmerkmalen zu - es wird nur ein Haufen visueller Geräusche. Wenn Sie jedoch nicht eine ganze Reihe von Namen aus demstd
Namespace in Ihrem Code verwenden, sehe ich auch kein Problem darin, die Direktive wegzulassen. Es ist eine Tautologie - wenn die Richtlinie nicht erforderlich ist, muss sie nicht verwendet werden.Ebenso, wenn Sie mit ein paar using-Deklarationen (anstelle von using-Direktiven ) für bestimmte Typen in der
std
Namespace , gibt es keinen Grund, warum Sie nicht nur diese spezifischen Namen in den aktuellen Namespace einfügen sollten. Aus dem gleichen Grund denke ich, dass es verrückt und ein Aufwand für die Buchhaltung wäre, 25 oder 30 Verwendungserklärungen zu haben, wenn eine einzige Verwendungsrichtlinie den Trick genauso gut machen würde.Es ist auch gut im Auge zu behalten , dass es Zeiten , in denen Sie müssen eine using-Deklaration verwenden. Siehe Scott Meyers '"Punkt 25: Unterstützung für einen nicht werfenden Swap in Betracht ziehen" aus Effective C ++, Third Edition. Damit eine generische Funktion mit Vorlagen die 'beste' Swap-Methode für einen parametrisierten Typ verwenden kann, müssen Sie eine using-Deklaration und eine argumentabhängige Suche (auch bekannt als ADL- oder Koenig-Lookup) verwenden:
Ich denke, wir sollten uns die gemeinsamen Redewendungen für verschiedene Sprachen ansehen, die Namespaces in erheblichem Maße nutzen. Beispielsweise verwenden Java und C # in großem Umfang Namespaces (wahrscheinlich mehr als C ++). Die gebräuchlichste Art und Weise, wie Namen in Namespaces in diesen Sprachen verwendet werden, besteht darin, sie massenhaft mit dem Äquivalent einer using-Direktive in den aktuellen Geltungsbereich zu bringen. Dies führt nicht zu weit verbreiteten Problemen, und die wenigen Male, bei denen es sich um ein Problem handelt, werden auf Ausnahmebasis behandelt, indem die betreffenden Namen über vollständig qualifizierte Namen oder durch Aliasing behandelt werden - genau wie dies in C ++ möglich ist.
Herb Sutter und Andrei Alexandrescu haben dies in "Punkt 59: Schreiben Sie keine Namespace-Verwendungen in eine Header-Datei oder vor einem #include" ihres Buches C ++ Coding Standards: 101 Regeln, Richtlinien und Best Practices zu sagen:
Stroupstrup wird in "The C ++ Programming Language, Third Edition" häufig mit den Worten "Verschmutzen Sie nicht den globalen Namespace" zitiert. Er sagt das tatsächlich (C.14 [15]), bezieht sich aber auf Kapitel C.10.1, in dem er sagt:
Und wie hat man den gleichen Vorteil wie ein "fauler Benutzer globaler Namen"? Durch die Nutzung der using-Direktive, die Namen in einem Namespace sicher für den aktuellen Bereich verfügbar macht.
Beachten Sie, dass es einen Unterschied gibt - Namen im
std
Namespace, die einem Bereich mit der richtigen Verwendung einer using-Direktive (durch Platzieren der Direktive nach dem#includes
) zur Verfügung gestellt werden , verschmutzen den globalen Namespace nicht. Es geht nur darum, diese Namen leicht verfügbar zu machen und sie weiterhin vor Zusammenstößen zu schützen.quelle
std::
Qualifikationsmerkmale den Code nicht überladen - es gibt andere Möglichkeiten, dies zu vermeiden (using-Deklarationen oder typedefs reichen normalerweise aus).using namespace std;
Anweisung " " hindert Sie nicht daran, Ihre natürliche Kennung zu deklarierenlist
"- es ist nur so, dass Sie dies nicht können, wenn Sie dies tun länger verwenden,std::list
ohne es zu qualifizieren. Das ist nicht anders, als wenn es keine "using namespace std;
" Richtlinie gibt. Oder fehlt mir etwas?Verwenden Sie niemals den Namespace im globalen Bereich in einer Header-Datei. Dies kann zu Konflikten führen, und die verantwortliche Person für die Datei, in der der Konflikt auftritt, hat keine Kontrolle über die Ursache.
In der Implementierungsdatei sind die Auswahlmöglichkeiten weitaus weniger gut.
Wenn Sie einen using-Namespace std einfügen, werden alle Symbole aus diesen Namespaces angezeigt. Dies kann problematisch sein, da fast kein Körper alle vorhandenen Symbole kennt (daher ist es in der Praxis unmöglich, eine Politik ohne Konflikte anzuwenden), ohne von den Symbolen zu sprechen, die hinzugefügt werden. Und der C ++ - Standard erlaubt es einem Header, Symbole aus anderen Headern hinzuzufügen (der C-Standard erlaubt das nicht). In der Praxis kann es immer noch gut funktionieren, das Schreiben im kontrollierten Fall zu vereinfachen. Und wenn ein Fehler auftritt, wird er in der Datei erkannt, in der das Problem auftritt.
Putten mit std :: name; hat den Vorteil einer einfachen Schreibweise ohne das Risiko, unbekannte Symbole zu importieren. Die Kosten sind, dass Sie explizit alle gewünschten Symbole importieren müssen.
Das explizite Qualifizieren bringt ein wenig Unordnung mit sich, aber ich denke, es ist weniger schwierig, etwas zu üben.
In meinem Projekt verwende ich eine explizite Qualifikation für alle Namen, ich akzeptiere die Verwendung von std :: name, ich kämpfe gegen die Verwendung des Namespace std (wir haben einen Lisp-Interpreter, der seinen eigenen Listentyp hat und Konflikte sind daher eine sichere Sache).
Bei anderen Namespaces müssen Sie auch die verwendeten Namenskonventionen berücksichtigen. Ich kenne ein Projekt, das einen Namespace (für die Versionierung) und ein Präfix für Namen verwendet. Ein
using namespace X
dann zu machen ist fast ohne Risiko und es nicht zu tun, führt zu dumm aussehendem CodePrefixNS::pfxMyFunction(...)
.In einigen Fällen möchten Sie die Symbole importieren. std :: swap ist der häufigste Fall: Sie importieren std :: swap und verwenden dann swap unqualifiziert. Die argumentabhängige Suche findet einen angemessenen Austausch im Namespace des Typs, falls vorhanden, und greift auf die Standardvorlage zurück, wenn keine vorhanden ist.
Bearbeiten:
In den Kommentaren fragt sich Michael Burr, ob die Konflikte in der realen Welt auftreten. Hier ist ein echtes Live-Beispiel. Wir haben eine Erweiterungssprache mit einem Lisp-Dialekt. Unser Interpreter hat eine Include-Datei, die lisp.h enthält
Wir mussten einen Code (den ich "Engine" nennen werde) integrieren und anpassen, der so aussah:
Also haben wir so modifiziert:
Gut. Alles funktioniert. Einige Monate später wurde "module.h" geändert, um "list.h" aufzunehmen. Die Tests bestanden. "module" wurde nicht in einer Weise geändert, die sich auf das ABI auswirkte, sodass die "engine" -Bibliothek verwendet werden konnte, ohne die Benutzer neu zu kompilieren. Integrationstests waren in Ordnung. Neues "Modul" veröffentlicht. Die nächste Kompilierung der Engine ist unterbrochen, wenn der Code nicht geändert wurde.
quelle
Wenn Sie kein Risiko für Namenskonflikte in Ihrem Code mit std und anderen Bibliotheken haben, können Sie Folgendes verwenden:
Wenn Sie jedoch die Abhängigkeit Ihres Codes für die Dokumentation genau kennen möchten oder das Risiko von Namenskonflikten besteht, verwenden Sie die andere Methode:
Die dritte Lösung, verwenden Sie diese Lösungen nicht und schreiben Sie std ::, bevor jede Verwendung im Code Ihnen mehr Sicherheit bringt, aber vielleicht ein wenig Schwere im Code ...
quelle
Beide
und
Fügen Sie dem globalen Namespace einige Symbole (eines oder viele) hinzu. Das Hinzufügen von Symbolen zum globalen Namespace sollten Sie in Header-Dateien niemals tun. Sie haben keine Kontrolle darüber, wer Ihren Header enthält. Es gibt viele Header, die andere Header enthalten (und Header, die Header enthalten, die Header enthalten usw.).
In Implementierungsdateien (.cpp) liegt es an Ihnen (denken Sie nur daran, dies nach allen # include-Anweisungen zu tun ). Sie können nur Code in dieser bestimmten Datei brechen, um den Grund für Namenskonflikte einfacher zu verwalten und herauszufinden. Wenn Sie std :: (oder ein anderes Präfix, es können viele Namespaces in Ihrem Projekt vorhanden sein) vor den Einrückern bevorzugen, ist dies in Ordnung. Wenn Sie dem globalen Namespace Bezeichner hinzufügen möchten, ist dies in Ordnung. Wenn Sie einen ganzen Namespace auf Ihren Kopf bringen wollen :-), liegt es an Ihnen. Die Effekte sind zwar auf eine einzelne Kompilierungseinheit beschränkt, aber akzeptabel.
quelle
Für mich bevorzuge ich,
::
wenn möglich.Ich hasse es zu schreiben:
Hoffentlich würde ich mit C ++ 0x Folgendes schreiben:
Wenn der Namespace sehr lang ist,
quelle
++i
, nichti++
weil, wenn es überhaupt definiert ist, eine unnötige temporäre Kopie des Iterators erstellt wird.Sie sollten sich niemals
using namespace std
im Namespace-Bereich eines Headers befinden. Ich nehme an, die meisten Programmierer werden sich fragen, wann sie sehenvector
oderstring
nichtstd::
, also denke ich, dass es nichtusing namespace std
besser ist. Dafür plädiere ich dafür, niemals zu seinusing namespace std
.Wenn Sie das Gefühl haben, dass Sie müssen, fügen Sie local mit Deklarationen wie hinzu
using std::vector
. Aber fragen Sie sich: Was ist das wert? Eine Codezeile wird einmal (vielleicht zweimal) geschrieben, aber zehn-, hundert- oder tausendmal gelesen. Der gespeicherte Schreibaufwand beim Hinzufügen einer using-Deklaration oder Direktive ist im Vergleich zum Aufwand beim Lesen des Codes gering.Vor diesem Hintergrund haben wir vor zehn Jahren in einem Projekt beschlossen, alle Bezeichner explizit mit ihren vollständigen Namespace-Namen zu qualifizieren. Was zunächst unangenehm schien, wurde innerhalb von zwei Wochen zur Routine. Jetzt verwendet in allen Projekten des gesamten Unternehmens niemand mehr Richtlinien oder Erklärungen. (Mit einer Ausnahme siehe unten.) Wenn ich mir den Code (mehrere MLoC) nach zehn Jahren anschaue, habe ich das Gefühl, dass wir die richtige Entscheidung getroffen haben.
Ich habe festgestellt, dass diejenigen, die sich dem Verbot widersetzen, es
using
normalerweise nicht für ein Projekt ausprobiert haben. Diejenigen, die es versucht haben, finden es oft besser, als nach sehr kurzer Zeit Richtlinien / Erklärungen zu verwenden.Hinweis: Die einzige Ausnahme ist
using std::swap
die, die erforderlich ist (insbesondere im generischen Code), um Überladungen aufzunehmenswap()
, die nicht in denstd
Namespace eingefügt werden können (da wir keine Überladungen vonstd
Funktionen in diesen Namespace einfügen dürfen).quelle
std
, aber nicht überladen. Entschuldigung für diesen Brainfart. Ich werde den Beitrag korrigieren.using namespace
Richtlinie darin bestand, das Tippen zu machen . Vielmehr sollte es das Lesen erleichtern, da dieser Code, wie Sie sagen, Dutzende, Hunderte oder Tausende Male gelesen werden muss. Und für einige Leute liest es sich viel einfacher mit wenigerstd::
Unordnung. Aber das hängt wahrscheinlich von der persönlichen Wahrnehmungsfähigkeit ab; Einige Leute filternstd::
weg oder brauchen es sogar zur Führung (wie Serifen), andere stolpern darauf und fühlen sich wie auf einer holprigen Straße.Namespaces enthalten Code, um Verwirrung und Verschmutzung der Funktionssignaturen zu vermeiden .
Hier ist eine vollständige und dokumentierte Demo der richtigen Verwendung von Namespaces :
Ausgabe:
quelle
using namespace std
Importiert den Inhalt desstd
Namespace in den aktuellen. Der Vorteil ist also, dass Sie nichtstd::
vor allen Funktionen dieses Namespace tippen müssen . Es kann jedoch vorkommen, dass Sie unterschiedliche Namespaces mit gleichnamigen Funktionen haben. Daher können Sie damit enden, nicht den gewünschten anzurufen.Wenn Sie manuell angeben, in welche Dateien Sie importieren möchten, wird dies
std
verhindert. Dies kann jedoch zu einer langen Liste von Verwendungszwecken am Anfang Ihrer Datei führen, die einige Entwickler als hässlich empfinden.Persönlich bevorzuge ich es, den Namespace jedes Mal anzugeben, wenn ich eine Funktion verwende, außer wenn der Namespace zu lang ist. In diesem Fall setze ich einen am Anfang der Datei.
BEARBEITEN: Wie in einer anderen Antwort angegeben, sollten Sie niemals eine
using namespace
in eine Header-Datei einfügen, da diese an alle Dateien einschließlich dieses Headers weitergegeben wird und daher zu unerwünschtem Verhalten führen kann.EDIT2: korrigierte meine Antwort dank Charles Kommentar.
quelle
using namespace std;
Importiert den Inhalt desstd
Namespace in den globalen Namespace. Der Standard-Namespace wird nicht geändert. Wenn Sie etwas im globalen Namespace nach a definieren,using namespace std
wird es nicht auf magische Weise in denstd
Namespace eingefügt.Ähnlich wie in Java, wo Sie entweder java.util. * Einschließen oder einfach jede Klasse einzeln auswählen können, hängt dies vom Stil ab. Beachten Sie, dass Sie
using namespace std
am Anfang Ihrer Datei / Ihres weiten Bereichs keinen möchten, da Sie den Namespace verschmutzen und möglicherweise Konflikte verursachen, wodurch der Punkt der Namespaces zunichte gemacht wird. Wenn Sie jedoch eine Funktion haben, die viel STL verwendet, wird der Code so durcheinander gebracht, dass die Logik ein Durcheinander von Präfixsyntax enthält, und Sie sollten wahrscheinlich in Betracht ziehen, entwederusing namespace std
(bei Verwendung verschiedener Klassen) oder einzelneusing
s (bei Verwendung einiger weniger) zu verwenden Klassen oft).quelle
Diese Diskussion wird so lange lebendig sein, wie die IDE, mit der Sie arbeiten, nicht flexibel genug ist, um die genauen Informationen anzuzeigen oder auszublenden, die Sie benötigen.
Das liegt daran, dass es von der jeweiligen Aufgabe abhängt, wie Ihr Code aussehen soll.
Beim Erstellen meines Quellcodes möchte ich lieber genau sehen, welche Klasse ich verwende: Ist es
std::string
oder dieBuzFlox::Obs::string
Klasse?Beim Entwerfen des Kontrollflusses interessieren mich nicht einmal die Arten der Variablen, aber ich möchte mich auf
if
'swhile
' undcontinue
's ' und 's konzentrieren.Das ist also mein Rat:
Wählen Sie abhängig von der Zielgruppe Ihres Codes und der Leistung Ihrer Tools die Art und Weise, die entweder am einfachsten zu lesen ist oder die meisten Informationen liefert.
quelle
Es gibt verschiedene Möglichkeiten, dies zu beheben.
Erstens: Verwenden Sie wie das, was Sie getan haben.
Zweitens:
namespace S = std;
Reduzieren Sie 2 Zeichen.Drittens: verwenden
static
.Viertens: Verwenden Sie keine Namen, die
std
verwenden.quelle
Der einzige Grund, auf std :: zu verzichten, besteht darin, dass Sie theoretisch alle STL-Funktionen selbst neu implementieren können. Dann könnten Ihre Funktionen von std :: vector auf my :: vector umgestellt werden, ohne den Code zu ändern.
quelle
Warum nicht zum Beispiel
statt der unhandlichen
Ich finde das viel lesbarer und es ist mein Standard für die Codierung.
Sie können es sogar verwenden, um einige semantische Informationen für den Leser einzuschließen. Betrachten Sie beispielsweise die Funktionsprototypen
Welches ist der Rückgabewert?
Wie wäre es stattdessen
quelle