3261 Stimmen

Warum wird "using namespace std;" als schlechte Praxis angesehen?

Ich habe von anderen gehört, dass das Schreiben using namespace std; im Code falsch ist, und dass ich Folgendes verwenden sollte std::cout y std::cin stattdessen direkt.

Warum ist using namespace std; eine schlechte Praxis? Ist es ineffizient oder besteht die Gefahr, dass mehrdeutige Variablen deklariert werden (Variablen, die denselben Namen haben wie eine Funktion in std Namespace)? Wirkt sich das auf die Leistung aus?

710 Stimmen

Vergessen Sie nicht, was Sie tun können: "using std::cout;", was bedeutet, dass Sie nicht std::cout eingeben müssen, aber nicht gleichzeitig den gesamten std-Namensraum mit einbeziehen.

115 Stimmen

Es ist besonders schlecht, 'using namespace std' in Headerdateien im Dateisystem zu verwenden. Die Verwendung in Quelldateien (*.cpp) im Dateisystem nach allen Includes ist nicht ganz so schlimm, da ihre Wirkung auf eine einzige Übersetzungseinheit beschränkt ist. Noch weniger problematisch ist die Verwendung innerhalb von Funktionen oder Klassen, da die Wirkung auf den Funktions- oder Klassenbereich beschränkt ist.

15 Stimmen

Ich würde davon abraten, die using-Direktive zu verwenden, aber für bestimmte Namespaces wie std::literals::chrono_literals , Poco::Data:Keywords , Poco::Units und andere Dinge, die mit Literalen oder Lesbarkeitstricks zu tun haben. Immer dann, wenn es in Header- oder Implementierungsdateien steht. In einem Funktionsbereich mag es in Ordnung sein, aber abgesehen von Literalen und anderen Dingen ist es nicht nützlich.

2768voto

Greg Hewgill Punkte 882617

Dies hat nichts mit der Leistung zu tun. Aber bedenken Sie Folgendes: Sie verwenden zwei Bibliotheken namens Foo und Bar:

using namespace foo;
using namespace bar;

Alles funktioniert einwandfrei, und Sie können die Blah() von Foo und Quux() von Bar ohne Probleme. Aber eines Tages aktualisieren Sie auf eine neue Version von Foo 2.0, die nun eine Funktion namens Quux() . Jetzt haben Sie einen Konflikt: Sowohl Foo 2.0 als auch Bar importieren Quux() in Ihren globalen Namespace. Es wird einige Mühe kosten, dies zu beheben, insbesondere wenn die Funktionsparameter übereinstimmen.

Hätten Sie die foo::Blah() y bar::Quux() , dann die Einführung von foo::Quux() wäre ein Nicht-Ereignis gewesen.

2 Stimmen

Diese Antwort sollte erweitert werden, um weitere Punkte anzusprechen: - Unterschied zwischen der Verwendung in einer Header-Datei und der Verwendung in einer cpp-Datei. - Unterschied zwischen std und einem anderen Namensraum, d.h. warum ist std unter allen Namensräumen hervorgehoben. Ist es sicherer, die boost wie das?

1 Stimmen

boost y std sind die häufigsten Arten, Konflikte zu haben. fileystem , string , shared_ptr usw., fast alles in std existiert in gleicher Weise auch in boost und mit der Zeit werden wahrscheinlich noch weitere Dinge hinzukommen.

572 Stimmen

Ich mochte schon immer Pythons "import big_honkin_name as bhn", so dass Sie dann nur "bhn.something" statt "big_honkin_name.something" verwenden können - wirklich reduziert die Typisierung. Gibt es so etwas auch in C++?

1661voto

sbi Punkte 211669

Ich bin mit allem einverstanden Greg schrieb aber ich möchte noch etwas hinzufügen: Es kann sogar noch schlimmer kommen, als Greg gesagt hat!

Die Bibliothek Foo 2.0 könnte eine Funktion einführen, Quux() die eindeutig besser zu einigen Ihrer Aufrufe an Quux() als die bar::Quux() Ihr Code wird seit Jahren aufgerufen. Dann wird Ihr Code lässt sich noch kompilieren aber ruft er stillschweigend die falsche Funktion auf und tut Gott-weiß-was. Schlimmer kann es nicht mehr werden.

Beachten Sie, dass die std Namespace hat eine Vielzahl von Bezeichnern, von denen viele sehr gemeinsame (denken Sie an list , sort , string , iterator usw.), die mit großer Wahrscheinlichkeit auch in anderem Code vorkommen.

Wenn Sie dies für unwahrscheinlich halten: Es gab eine gestellte Frage hier auf Stack Overflow, wo so ziemlich genau das passiert ist (falsche Funktion aufgerufen aufgrund von ausgelassenen std:: Präfix), etwa ein halbes Jahr nachdem ich diese Antwort gegeben habe. Ici ist ein weiteres, jüngeres Beispiel für eine solche Frage. Dies ist also ein echtes Problem.


Hier ist ein weiterer Datenpunkt: Vor vielen, vielen Jahren habe ich es auch als lästig empfunden, allem aus der Standardbibliothek das Präfix std:: . Dann arbeitete ich an einem Projekt, bei dem zu Beginn beschlossen wurde, dass beide using Direktiven und Deklarationen sind verboten, außer für Funktionsbereiche. Und nun raten Sie mal! Die meisten von uns brauchten nur wenige Wochen, um sich an die Schreibweise des Präfixes zu gewöhnen, und nach ein paar weiteren Wochen waren sich die meisten von uns sogar einig, dass der Code dadurch tatsächlich besser wurde besser lesbar . Dafür gibt es einen Grund: Ob man kürzere oder längere Prosa mag, ist subjektiv, aber die Präfixe tragen objektiv zur Klarheit des Codes bei. Nicht nur für den Compiler, sondern auch für Sie ist es einfacher zu erkennen, auf welchen Bezeichner er sich bezieht.

Innerhalb eines Jahrzehnts wuchs dieses Projekt auf mehrere Millionen Codezeilen an. Da diese Diskussionen immer wieder auftauchen, war ich einmal neugierig, wie oft der (erlaubte) Funktionsumfang using tatsächlich in dem Projekt verwendet wurde. Ich habe die Quellen danach durchsucht und nur ein oder zwei Dutzend Stellen gefunden, an denen es verwendet wurde. Für mich ist das ein Hinweis darauf, dass Entwickler, wenn sie es einmal ausprobiert haben, nicht finden std:: schmerzhaft genug, um die Verwendung von Richtlinien auch nur alle 100 kLoC zuzulassen, selbst dort, wo die Verwendung erlaubt war.


Unterm Strich: Alles explizit voranzustellen schadet nicht, ist sehr gewöhnungsbedürftig und hat objektive Vorteile. Insbesondere macht es den Code für den Compiler und den menschlichen Leser leichter zu interpretieren - und das sollte wohl das Hauptziel beim Schreiben von Code sein.

1 Stimmen

Unklarheit über die Interpretation durch den Leser, da foo::bar() die Funktion bar aus dem Namespace foo oder eine statische Funktion der Klasse foo bedeuten kann.

5 Stimmen

@convert Und warum sollte jemand eine Klasse foo 代わりに Foo ? Und statische Methoden sollten auch aufgerufen werden Foo::Bar y no Foo::bar . Deshalb dachten die Leute, dass Kongresse eine gute Sache sind.

0 Stimmen

@Stefan Riedel Ich weiß es nicht, aber es ist gängige Praxis in C++. Zum Beispiel heißt es String und Vektor und nicht String und Vektor.

564voto

ChrisW Punkte 53239

Das Problem bei der Umsetzung using namespace in den Header-Dateien Ihrer Klassen ist, dass es jeden, der Ihre Klassen benutzen will (indem er Ihre Header-Dateien einbezieht), dazu zwingt, auch diese anderen Namensräume zu "benutzen" (d.h. alles in ihnen zu sehen).

Es steht Ihnen jedoch frei, eine using-Anweisung in Ihre (privaten) *.cpp-Dateien einzufügen.


Beachten Sie, dass einige Leute nicht damit einverstanden sind, dass ich "sich frei fühlen" so sage - denn obwohl ein using Anweisung in einer cpp-Datei ist besser als in einem Header (weil es die Leute, die Ihre Header-Datei einbinden, nicht beeinträchtigt), denken sie, dass es immer noch nicht gut (denn je nach Code könnte es die Implementierung der Klasse schwieriger machen, sie zu pflegen). Dieser C++ Super-FAQ-Eintrag sagt,

Die using-Anweisung existiert für alten C++-Code und um den Übergang zu Namespaces zu erleichtern, aber Sie sollten sie wahrscheinlich nicht regelmäßig verwenden, zumindest nicht in Ihrem neuen C++-Code.

In den FAQ werden zwei Alternativen vorgeschlagen:

  • Eine using-Deklaration:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
  • Geben Sie einfach std: ein:

    std::cout << "Values:";

9 Stimmen

Natürlich sollte man auch nie den Zustand des globalen cout annehmen, damit nicht jemand std:cout << std::hex hat und danach std::restore_cout_state versäumt. Aber das ist ein ganz anderer Fettberg.

0 Stimmen

"Sie können jedoch gerne eine using-Anweisung in Ihre (privaten) *.cpp-Dateien einfügen." Und was ist, wenn ein zukünftiges Entwicklerteam beschließt, das Schema der Übersetzungseinheiten zu ändern, zum Beispiel über UnityBuilds? Im Zweifelsfall werden Sie mit einem schrecklichen undefinierten Verhalten enden.

0 Stimmen

Während die Bedenken in Bezug auf Header-Dateien gerechtfertigt sein können, weil Include-Dateien Nebenwirkungen haben können, bin ich der Meinung, dass dies im Fall von cpp-Dateien nicht der Fall ist. Schauen wir uns einmal an, was in praktisch jeder anderen Programmiersprache passiert. Wenn Sie z. B. in Java programmieren, importieren Sie fast immer jedes Symbol aus den verwendeten Paketen - insbesondere aus den Standardpaketen. Das bedeutet, dass Sie fast nie eine konkurrierende und widersprüchliche Implementierung von String, List, Map usw. erwarten. Das Gleiche gilt für andere Sprachen, die ich kenne. IMO ist das vernünftig, und wir sollten das Leben einfach machen, nicht schwer.

273voto

David Thornley Punkte 55244

Kürzlich stieß ich auf eine Beschwerde über Visual Studio 2010 . Es stellte sich heraus, dass so gut wie alle Quelldateien diese beiden Zeilen enthielten:

using namespace std;
using namespace boost;

Eine Vielzahl von Boost Features gehen in den C++0x-Standard über, und Visual Studio 2010 verfügt über viele C++0x-Features, sodass diese Programme plötzlich nicht mehr kompiliert werden konnten.

Daher ist die Vermeidung von using namespace X; ist eine Form der Zukunftssicherung, ein Weg, um sicherzustellen, dass eine Änderung an den verwendeten Bibliotheken und/oder Header-Dateien ein Programm nicht kaputt macht.

31 Stimmen

Dies. Boost und std haben eine Los von Überschneidungen - insbesondere seit C++11.

2 Stimmen

Ich habe das einmal gemacht und eine Lektion auf die harte Tour gelernt. Jetzt benutze ich nie using außerhalb einer Funktionsdefinition und verwenden selten using namespace überhaupt nicht.

0 Stimmen

Ich persönlich würde niemals Boost verwenden, da es die schlechteste C++-API ist, die ich je gesehen habe. Welche Probleme könnte ich dann noch haben, wenn ich den Namespace std verwende?

236voto

mattnewport Punkte 13240

Kurzversion: Verwenden Sie keine globalen using Deklarationen oder Direktiven in Header-Dateien. Es steht Ihnen frei, sie in Implementierungsdateien zu verwenden. So sieht es aus Herb Sutter y Andrei Alexandrescu zu diesem Thema zu sagen haben in C++-Codierungsstandards (die Hervorhebungen stammen von mir):

Zusammenfassung

Die Verwendung von Namensräumen dient Ihrer Bequemlichkeit und nicht dazu, sie anderen aufzudrängen: Schreiben Sie niemals eine using-Deklaration oder eine using-Anweisung vor einer #include-Anweisung.

Korollarisch: Schreiben Sie in Header-Dateien nicht auf Namespace-Ebene, indem Sie Direktiven oder Deklarationen verwenden; stattdessen sollten Sie alle Namen explizit auf Namespace-Ebene qualifizieren. (Die zweite Regel folgt aus der ersten, weil Header nie wissen können, welche anderen Header #includes nach ihnen erscheinen könnten).

Discusión

Kurz gesagt: Sie können und sollten Namespace using-Deklarationen und Direktiven in Ihren Implementierungsdateien nach #include-Direktiven großzügig verwenden und sich dabei gut fühlen. Trotz wiederholter gegenteiliger Behauptungen sind Deklarationen und Direktiven zur Verwendung von Namespaces nichts Böses und sie vereiteln nicht den Zweck von Namespaces. Vielmehr sind sie es, die Namespaces nutzbar machen .

13 Stimmen

Dies ist nur die Meinung eines weiteren Programmierers, aber ich stimme zu 100% mit der Aussage überein, dass das Wort using nie in einer Kopfzeile erscheinen sollte, bin ich nicht so überzeugt von der freien Lizenz zur Platzierung using namespace xyz; irgendwo in Ihrem Code, besonders wenn xyz est std . Ich verwende die using std::vector; Form, da dadurch nur ein einzelnes Element aus dem Namespace in den pseudoglobalen Bereich gezogen wird, was das Risiko einer Kollision deutlich verringert.

7 Stimmen

@Lightness Races in Orbit Sie haben natürlich ein Recht auf Ihre Meinung. Es wäre hilfreicher gewesen, wenn Sie versucht hätten zu erklären, warum Sie mit den in dieser Antwort gegebenen Ratschlägen nicht einverstanden sind. Insbesondere wäre es interessant zu verstehen, was der Sinn von Namespaces ist, wenn es schlecht ist, sie zu "benutzen"? Warum nennt man Dinge nicht einfach std_cout statt std::cout ... die Schöpfer von C++/Namensraum müssen eine Idee gehabt haben, als sie sich die Mühe machten, sie zu schaffen.

1 Stimmen

@nyholku: Nicht nötig - die meisten anderen Antworten geben die gleichen Gründe an, die ich auch nennen würde. Bitte zögern Sie auch nicht, das ":)" zu beachten. das ich an meinen Kommentar angehängt habe! Und dass ich nicht gesagt habe, dass Namespaces schlecht sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X