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.

144voto

robson3.14 Punkte 2950

Man sollte nicht die using Richtlinie im globalen Bereich, insbesondere in Headern. Es gibt jedoch Situationen, in denen sie auch 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 eine ausdrückliche Qualifizierung ( std::sin , std::cos ...), weil es kürzer ist und mit benutzerdefinierten Gleitkommatypen arbeiten kann (über argumentabhängiges Nachschlagen (ADL)).

4 Stimmen

@Billy: Es gibt keine andere Möglichkeit, den Aufruf von userlib::cos(userlib::superint) zu unterstützen. Jede Funktion hat einen Nutzen.

19 Stimmen

@Zan: Natürlich gibt es das. using std::cos; , using std::sin , usw. Das Problem ist jedoch, dass jede gut konzipierte userlib wird ihre sin y cos in ihrem eigenen Namespace, so dass dies Ihnen nicht wirklich hilft. (Es sei denn, es gibt eine using namespace userlib vor dieser Vorlage und das ist genauso schlimm wie using namespace std -- und der Umfang ist dort nicht begrenzt). Darüber hinaus ist die einzige Funktion, bei der ich so etwas je gesehen habe swap und in solchen Fällen würde ich empfehlen, einfach eine Vorlagenspezialisierung von std::swap und das ganze Problem zu vermeiden.

1 Stimmen

@Billy: Manchmal muss man das Überlastung tauschen (z. B. wenn Sie sie für Ihren eigenen Container benötigen). Aber selbst dann ist ein lokaler mit Erklärung ist viel besser als eine using-Anweisung.

114voto

towi Punkte 21168

Verwenden Sie es nicht global

Sie wird nur dann als "schlecht" angesehen, wenn weltweit eingesetzt . Weil:

  • Sie bringen den Namensraum, in dem Sie programmieren, durcheinander.
  • Die Leser werden Schwierigkeiten haben zu erkennen, woher ein bestimmter Identifikator kommt, wenn Sie viele using namespace xyz; .
  • Was auch immer gilt für andere Leser Ihres Quellcodes ist, gilt noch mehr für den häufigsten Leser: Sie selbst. Kommen Sie in ein oder zwei Jahren wieder und sehen Sie sich das an...
  • Wenn Sie nur über using namespace std; Sie sind sich vielleicht gar nicht bewusst, was Sie da alles mitnehmen - und wenn Sie eine weitere #include oder zu einer neuen C++-Revision wechseln, kann es zu Namenskonflikten kommen, die Ihnen nicht bewusst waren.

Sie können es lokal verwenden

Sie können es lokal (fast) frei verwenden. Dies verhindert natürlich die Wiederholung von std:: -- und Wiederholungen sind auch schlecht.

Eine Redewendung für die lokale Nutzung

Unter C++03 gab es eine Redewendung -- Code aus dem Baukasten -- für die Umsetzung einer swap Funktion für Ihre Klassen. Es wurde vorgeschlagen, dass Sie tatsächlich eine lokale 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 bewirkt die folgende Magie:

  • Der Compiler wählt die std::swap pour value_ d.h. void std::swap(int, int) .
  • Wenn Sie eine Überlastung haben void swap(Child&, Child&) implementiert ist, wird der Compiler sie auswählen.
  • Wenn Sie das tun no diese Überladung haben, verwendet der Compiler void std::swap(Child&,Child&) und versuchen Sie Ihr Bestes, um diese zu tauschen.

Mit C++11 gibt es keinen Grund mehr, dieses Muster zu verwenden. Die Implementierung von std::swap wurde geändert, um eine potenzielle Überlast zu finden und diese auszuwählen.

7 Stimmen

"Die Implementierung von std::swap wurde geändert, um eine potentielle Überladung zu finden und diese auszuwählen." - Was ist das? Sind Sie sich da sicher? Es ist zwar richtig, dass die Bereitstellung einer benutzerdefinierten swap ist in C++11 gar nicht mehr so wichtig, da die std::swap selbst ist flexibler (verwendet eine Verschiebungssemantik). Aber std::swap automatisch einen eigenen Tausch zu wählen, das ist mir völlig neu (und ich glaube es nicht wirklich).

0 Stimmen

@ChristianRau Ich denke schon, ja. Ich habe das irgendwo auf SO gelesen. Wir können immer fragen Howard dann sollte er es wissen. Ich bin Graben y Graben Nun...

0 Stimmen

@ChristianRau Kann im Moment keinen endgültigen Link finden (muss zurück zur Arbeit), aber ich habe n3490 y n1252

88voto

sth Punkte 210180

Wenn Sie die richtigen Header-Dateien importieren, haben Sie plötzlich Namen wie hex , left , plus ou count in Ihrem globalen Bereich. Dies mag überraschend sein, wenn Sie nicht wissen, dass std:: enthält diese Namen. Wenn Sie versuchen, diese Namen auch lokal zu verwenden, kann das zu ziemlicher Verwirrung führen.

Wenn alles Standardmaterial in einem eigenen Namespace liegt, müssen Sie sich nicht um Namenskollisionen mit Ihrem Code oder anderen Bibliotheken sorgen.

15 Stimmen

+1 nicht zu vergessen distance . trotzdem bevorzuge ich nicht-qualifizierte namen, wo immer es praktisch möglich ist, da dies die lesbarkeit für mich erhöht. außerdem denke ich, dass die tatsache, dass wir Dinge in der mündlichen sprache normalerweise nicht qualifizieren und bereit sind, zeit damit zu verbringen, mögliche mehrdeutigkeiten aufzulösen, bedeutet, dass es wertvoll ist, in der lage zu sein, zu verstehen, worüber man ohne Qualifikationen spricht, und auf Quellcode angewandt bedeutet das, dass er so strukturiert ist, dass es auch ohne Qualifikationen klar ist, worum es geht.

0 Stimmen

Fairerweise muss man aber sagen, dass man die meisten davon nicht hat, wenn man nicht auch <iomanip> . Trotzdem, gutes Argument.

1 Stimmen

@einpoklum Normalerweise müssen Sie nicht angeben <iomanip> um diese zu bekommen. Einschließlich <iostream> ist ausreichend für alle, die in GCC zum Beispiel gcc.godbolt.org/z/Kqx9q1

53voto

Erfahrene Programmierer verwenden alles, was ihre Probleme löst, und vermeiden alles, was neue Probleme schafft, und genau aus diesem Grund vermeiden sie Verwendungsdirektiven auf Header-Dateiebene.

Erfahrene Programmierer versuchen auch, die vollständige Qualifizierung von Namen innerhalb ihrer Quelldateien zu vermeiden. Ein kleiner Grund dafür ist, dass es nicht elegant ist, mehr Code zu schreiben, wenn weniger Code ausreichend ist es sei denn, es gibt gute Gründe . Ein wichtiger Grund dafür ist das Ausschalten der argumentabhängigen Suche (ADL).

Was sind diese gute Gründe ? Manchmal wollen Programmierer ADL ausdrücklich ausschalten, ein anderes Mal wollen sie disambiguieren.

Die folgenden Punkte sind also in Ordnung:

  1. Verwendungsrichtlinien auf Funktionsebene und Verwendungserklärungen innerhalb der Implementierungen von Funktionen
  2. Verwendungserklärungen auf Quelldateiebene innerhalb von Quelldateien
  3. (Manchmal) Verwendungsrichtlinien auf Quelldateiebene

53voto

Oleksiy Punkte 33680

Ich stimme zu, dass es nicht global verwendet werden sollte, aber es ist nicht so schlimm, es lokal zu verwenden, wie in einem namespace . Hier ist ein Beispiel aus "Die Programmiersprache C++" :

namespace My_lib {

    using namespace His_lib; // Everything from His_lib
    using namespace Her_lib; // Everything from Her_lib

    using His_lib::String; // Resolve potential clash in favor of His_lib
    using Her_lib::Vector; // Resolve potential clash in favor of Her_lib

}

In diesem Beispiel haben wir mögliche Namenskonflikte und Mehrdeutigkeiten, die sich aus ihrer Zusammensetzung ergeben, aufgelöst.

Namen, die dort explizit deklariert werden (einschließlich Namen, die durch using-Deklarationen wie His_lib::String ) haben Vorrang vor Namen, die in einem anderen Bereich durch eine Verwendungsanweisung ( using namespace Her_lib ).

0 Stimmen

Interessant ist, dass die meisten anderen Antworten vergessen haben, den Geltungsbereich des Namensraums zu definieren, indem sie einfach geschweifte Klammern verwenden {..}

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