Frage Warum wird "using namespace std" als schlechte Methode betrachtet?


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

Warum ist using namespace std eine schlechte Praxis angesehen? Ist es ineffizient oder besteht die Gefahr, dass mehrdeutige Variablen deklariert werden (Variablen, die denselben Namen wie eine Funktion in std Namensraum)? Beeinflusst es die Leistung?


2061
2017-09-21 03:08


Ursprung


Antworten:


Dies hängt nicht mit der Leistung zusammen. Aber bedenken Sie: Sie verwenden zwei Bibliotheken namens Foo und Bar:

using namespace foo;
using namespace bar;

Alles funktioniert gut, Sie können anrufen Blah() von Foo und Quux() von Bar ohne Probleme. Aber eines Tages aktualisierst du auf eine neue Version von Foo 2.0, die jetzt eine Funktion namens Quux(). Jetzt hast du einen Konflikt: Sowohl Foo 2.0 als auch Bar importieren Quux() in Ihren globalen Namespace. Dies wird einige Anstrengungen erfordern, insbesondere wenn die Funktionsparameter übereinstimmen.

Wenn du benutzt hättest foo::Blah() und bar::Quux(), dann die Einführung von foo::Quux() wäre ein Nicht-Ereignis gewesen.


1746
2017-09-21 03:13



Ich stimme allem zu Greg schrieb, aber ich möchte hinzufügen: Es kann sogar schlimmer kommen als Greg sagte!

Bibliothek Foo 2.0 könnte eine Funktion einführen, Quux(), das ist eine eindeutig bessere Übereinstimmung für einige Ihrer Anrufe an Quux() als das bar::Quux() Ihr Code forderte seit Jahren. Dann dein Der Code wird noch kompiliert, aber Es ruft still die falsche Funktion an und tut Gott weiß was. Das ist ungefähr so ​​schlimm, wie es die Dinge können.

Beachten Sie, dass die std Namensraum hat Tonnen von Identifikatoren, von denen viele sind sehr gemeinsame (denken list, sort, string, iteratorusw.), die sehr wahrscheinlich auch in anderem Code vorkommen.

Wenn Sie das für unwahrscheinlich halten: Da war eine Frage gestellt Hier bei Stack Overflow wo genau das passiert ist (falsche Funktion wegen weggelassen std:: Präfix) etwa ein halbes Jahr, nachdem ich diese Antwort gegeben habe. Hier ist ein anderes, neueres Beispiel für eine solche Frage. Das ist also ein echtes Problem.


Noch ein weiterer Datenpunkt: Vor vielen, vielen Jahren fand ich es auch nervig, alles aus der Standard-Bibliothek voranzustellen std::. Dann habe ich an einem Projekt gearbeitet, bei dem am Anfang beide entschieden wurden using Direktiven und Deklarationen sind außer für Funktionsbereiche verboten. Erraten Sie, was? Die meisten von uns brauchten nur wenige Wochen, um sich an das Schreiben des Präfixes zu gewöhnen, und nach ein paar Wochen waren die meisten von uns sogar der Meinung, dass der Code tatsächlich erstellt wurde lesbarer. Es gibt einen Grund dafür: Ob Sie kürzere oder längere Prosa mögen, ist subjektiv, aber die Präfixe fügen dem Code Klarheit hinzu. Nicht nur der Compiler, auch Sie finden es einfacher zu erkennen, auf welchen Bezeichner verwiesen wird.

In einem Jahrzehnt wuchs das Projekt auf mehrere Millionen Codezeilen. Da diese Diskussionen immer wieder aufkommen, war ich einmal neugierig wie oft der (erlaubte) Funktionsumfang ist usingwurde tatsächlich in dem Projekt verwendet. Ich habe mir die Quellen dafür angeguckt und nur ein oder zwei Dutzend Orte gefunden, wo es benutzt wurde. Für mich zeigt dies, dass Entwickler, einmal versucht, nicht finden std:: schmerzhaft genug, um selbst bei Verwendung von Direktiven sogar einmal alle 100 kLoC zu verwenden.


Fazit: Explizit alles voranzutreiben schadet nicht, erfordert wenig Gewöhnung und hat objektive Vorteile. Insbesondere macht es den Code leichter vom Compiler und von menschlichen Lesern zu interpretieren - und das sollte wahrscheinlich das Hauptziel beim Schreiben von Code sein.


1147
2017-09-21 09:26



Ich denke, es ist schlecht, es in die Header-Dateien deiner Klassen zu schreiben: weil du dann jeden zwingen würdest, der deine Klassen benutzen will (indem du deine Header-Dateien einfügst), dass er auch diese anderen Namespaces benutzt .

Sie können jedoch eine using-Anweisung in Ihre (privaten) * .cpp-Dateien einfügen.


Hüten Sie sich davor, dass einige Leute mit meinem Sprichwort "fühlen Sie sich frei" so nicht einverstanden sind - denn obwohl eine using-Anweisung in einer cpp-Datei ist besser als in einer Kopfzeile (weil es Leute nicht betrifft, die Ihre Header-Datei enthalten), denken sie, dass es immer noch nicht ist gut (weil es je nach Code die Implementierung der Klasse schwieriger machen könnte). Dieses FAQ-Thema sagt,

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

Es schlägt zwei Alternativen vor:

  • Eine Verwendungsdeklaration:

    using std::cout; // a using-declaration lets you use cout without qualification
    cout << "Values:";
    
  • Komm vorbei und gib einfach std ein:

    std::cout << "Values:";
    

308
2017-09-21 03:22



Ich habe vor kurzem eine Beschwerde über Visual Studio 2010. Es stellte sich heraus, dass so ziemlich alle Quelldateien diese zwei Zeilen hatten:

using namespace std;
using namespace boost;

Viel Boost Features gehen in den C ++ 0x-Standard und Visual Studio 2010 hat viele C ++ 0x-Features, so dass diese Programme plötzlich nicht kompiliert wurden.

Daher vermeiden using namespace X; ist eine Form der Zukunftssicherheit, eine Möglichkeit, sicherzustellen, dass eine Änderung an den verwendeten Bibliotheken und / oder Header-Dateien ein Programm nicht bricht.


197
2017-10-28 17:37



Kurzversion: Verwenden Sie keine globalen using-Deklarationen oder -Direktiven in Header-Dateien. Fühlen Sie sich frei, sie in Implementierungsdateien zu verwenden. Hier sind, was Herb Sutter und Andrei Alexandrescu zu diesem Thema zu sagen haben C ++ Codierstandards (Fettdruck ist mein)

Zusammenfassung

Namespace usings sind für Ihre Bequemlichkeit, nicht für Sie anderen zufügen: Schreiben Sie nie eine using-Deklaration oder eine using-Direktive vor einer # include-Direktive.

Korollar: Schreiben Sie in Header-Dateien nicht Namespace-Level mit Direktiven oder Deklarationen; Stattdessen werden alle Namen explizit durch Namespace qualifiziert. (Die zweite Regel folgt von der ersten, weil Header nie wissen können, welche anderen Header # includes nach ihnen erscheinen könnten.)

Diskussion

Kurz gesagt: Sie können und sollten den Namespace mit Deklarationen und Direktiven beliebig in Ihren Implementierungsdateien nach # include Direktiven verwenden und sich wohl fühlen. Trotz wiederholter gegenteiliger Behauptungen sind Namespaces, die Deklarationen und Anweisungen verwenden, nicht böse, und sie verhindern nicht den Zweck von Namespaces. Vielmehr machen sie Namespaces nutzbar.


159
2017-11-03 20:00



Man sollte nicht die Direktive im globalen Geltungsbereich benutzen, besonders in den Headern. Es gibt jedoch Situationen, in denen es sogar in einer Header-Datei angebracht ist:

template <typename FloatType> inline
FloatType compute_something(FloatType x)
{
    using namespace std; //no problem since scope is limited
    return exp(x) * (sin(x) - cos(x * 2) + sin(x * 3) - cos(x * 4));
}

Dies ist besser als explizite Qualifikation (std::sin, std::cos...) weil es kürzer ist und mit benutzerdefinierten Fließkommatypen arbeiten kann (über Argument Dependent Lookup).


103
2017-09-21 15:47



Benutze es nicht global

Es gilt nur dann als "schlecht", wenn global verwendet. Weil:

  • Sie verwirren den Namespace, in dem Sie programmieren.
  • Leser werden Schwierigkeiten haben zu erkennen, woher eine bestimmte Kennung kommt, wenn Sie viele verwenden using namespace xyz.
  • Was auch immer für wahr ist andere Leser Ihres Quelltextes sind noch mehr für den häufigsten Leser bestimmt: für sich selbst. Komm in ein oder zwei Jahren zurück und schau dich um ...
  • Wenn du nur darüber redest using namespace std Sie sind sich vielleicht nicht aller Dinge bewusst, die Sie greifen - und wenn Sie eine weitere hinzufügen #include Wenn Sie zu einer neuen C ++ - Revision wechseln, erhalten Sie möglicherweise Namenskonflikte, die Ihnen nicht bekannt waren.

Sie können es lokal verwenden

Mach weiter und benutze es lokal (fast) frei. Dies verhindert natürlich die Wiederholung von std:: - Und Wiederholung ist auch schlecht.

Ein Idiom für die lokale Verwendung

In C ++ 03 gab es einen Idiom - Boilerplate - Code zur Implementierung eines swap Funktion für Ihre Klassen. Es wurde vorgeschlagen, dass Sie tatsächlich einen lokalen verwenden using namespace std -- oder zumindest using std::swap:

class Thing {
    int    value_;
    Child  child_;
public:
    // ...
    friend void swap(Thing &a, Thing &b);
};
void swap(Thing &a, Thing &b) {
    using namespace std;      // make `std::swap` available
    // swap all members
    swap(a.value_, b.value_); // `std::stwap(int, int)`
    swap(a.child_, b.child_); // `swap(Child&,Child&)` or `std::swap(...)`
}

Dies tut die folgende Magie:

  • Der Compiler wählt die std::swap zum value_, d.h. void std::swap(int, int).
  • Wenn Sie eine Überlastung haben void swap(Child&, Child&) implementiert der Compiler wird es wählen.
  • Wenn Sie tun nicht habe diese Überladung der Compiler verwenden wird void std::swap(Child&,Child&) und versuche es am besten zu tauschen.

Mit C ++ 11 gibt es keinen Grund mehr, dieses Muster zu verwenden. Die Implementierung von std::swap wurde geändert, um eine mögliche Überlastung zu finden und es zu wählen.


80
2018-01-18 09:34