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.

14voto

Carl Punkte 41134

Ich stimme mit den anderen hier überein, aber ich möchte die Bedenken bezüglich der Lesbarkeit ansprechen - Sie können all das vermeiden, indem Sie einfach Typendefinitionen am Anfang Ihrer Datei, Funktion oder Klassendeklaration verwenden.

Ich verwende sie in der Regel in meiner Klassendeklaration, da die Methoden einer Klasse in der Regel mit ähnlichen Datentypen (den Mitgliedern) arbeiten und ein Typedef die Möglichkeit bietet, einen Namen zu vergeben, der im Zusammenhang mit der Klasse sinnvoll ist. Dies erleichtert die Lesbarkeit der Definitionen der Klassenmethoden.

// Header
class File
{
   typedef std::vector<std::string> Lines;
   Lines ReadLines();
}

und bei der Umsetzung:

// .cpp
Lines File::ReadLines()
{
    Lines lines;
    // Get them...
    return lines;
}

im Gegensatz zu:

// .cpp
vector<string> File::ReadLines()
{
    vector<string> lines;
    // Get them...
    return lines;
}

oder:

// .cpp
std::vector<std::string> File::ReadLines()
{
    std::vector<std::string> lines;
    // Get them...
    return lines;
}

0 Stimmen

Nur eine kleine Anmerkung: Obwohl typedef nützlich ist, würde ich erwägen, eine Klasse zu erstellen, die Lines repräsentiert, anstatt typedef zu verwenden.

13voto

Nithin Punkte 995

Ein Beispiel, bei dem using namespace std wirft einen Kompilierungsfehler wegen der Mehrdeutigkeit von count, das auch eine Funktion in der Algorithmusbibliothek ist.

#include <iostream>
#include <algorithm>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}

3 Stimmen

::count -Problem gelöst. Normalerweise haben Sie mehr Zeug aus dem std Namespaced als von anderswo, ergo behalten die using Namespace-Direktive könnte Ihnen Tipparbeit sparen.

0 Stimmen

Das eigentliche Problem dabei ist, dass C++ immer noch Globals ohne Namensraum hat. Dies und die Tatsache, dass "this" in Methoden implizit ist, verursacht so viele Fehler und Probleme, dass ich sie nicht einmal zählen kann, selbst mit der richtigen "count"-Variable. ;)

11voto

Swiss Frank Punkte 1647

Das ist eine Frage des Einzelfalls. Wir wollen die "Gesamtbetriebskosten" der Software über ihre Lebensdauer hinweg minimieren. Die Angabe "using namespace std" hat einige Kosten, aber no Ihre Verwendung hat auch einen Preis: die Lesbarkeit.

Es wird zu Recht darauf hingewiesen, dass Ihr Code nicht mehr kompiliert werden kann, wenn die Standardbibliothek neue Symbole und Definitionen einführt, und Sie möglicherweise gezwungen sind, Variablen umzubenennen. Langfristig ist dies jedoch wahrscheinlich gut, da künftige Maintainer kurzzeitig verwirrt oder abgelenkt sein werden, wenn Sie ein Schlüsselwort für einen überraschenden Zweck verwenden.

Sie haben keine wollen eine Vorlage namens vector zu haben, die nicht der Vektor ist, den alle anderen kennen. Und die Anzahl der neuen Definitionen, die auf diese Weise in die C++-Bibliothek eingeführt werden, ist so gering, dass sie vielleicht einfach nicht auftauchen. Dort ist Diese Art der Umstellung ist mit Kosten verbunden, die jedoch nicht hoch sind und durch die gewonnene Klarheit ausgeglichen werden. std Symbolnamen für andere Zwecke.

Angesichts der Anzahl von Klassen, Variablen und Funktionen ist die Angabe std:: auf jeden einzelnen könnte Ihren Code um 50 % aufblähen und es schwieriger machen, ihn zu verstehen. Ein Algorithmus oder ein Schritt in einer Methode, der auf einem Bildschirm voller Code aufgenommen werden konnte, erfordert nun ein Hin- und Herblättern, um ihm zu folgen. Das ist ein echter Kostenfaktor. Es mag sein, dass die Kosten nicht sehr hoch sind, aber diejenigen, die diese Kosten leugnen, sind unerfahren, dogmatisch oder haben einfach Unrecht.

Ich würde die folgenden Regeln vorschlagen:

  1. std unterscheidet sich von allen anderen Bibliotheken. Sie ist die einzige Bibliothek, die jeder kennen muss, und meiner Meinung nach ist sie am besten als Teil der Sprache zu betrachten. Allgemein gesprochen gibt es ein hervorragendes Argument für using namespace std auch wenn dies bei anderen Bibliotheken nicht der Fall ist.

  2. Zwingen Sie niemals dem Autor einer Kompiliereinheit (einer .cpp-Datei) die Entscheidung auf, indem Sie diese using in einer Kopfzeile. Immer die Entscheidung dem Verfasser der Kompiliereinheit überlassen. Selbst in einem Projekt, das sich für die Verwendung von using namespace std Überall kann es einige wenige Module geben, die am besten als Ausnahmen von dieser Regel gehandhabt werden.

  3. Auch wenn die Namespace-Funktion es ermöglicht, viele Module mit gleich definierten Symbolen zu haben, wird es verwirrend sein, dies zu tun. Halten Sie die Namen so weit wie möglich auseinander. Auch wenn Sie die Namespace-Funktion nicht verwenden, sollten Sie eine Klasse mit dem Namen foo y std führt eine Klasse namens foo ist es auf lange Sicht wahrscheinlich besser, die Klasse trotzdem umzubenennen.

  4. Eine Alternative zur Verwendung von Namespaces ist die manuelle Benennung von Symbolen durch Präfixe. Ich habe zwei Bibliotheken, die ich seit Jahrzehnten benutze, beide begannen als C-Bibliotheken, wo jede Symbol mit dem Präfix "AK" oder "SCWin" versehen ist. Im Allgemeinen ist dies vergleichbar mit der Vermeidung des "using"-Konstrukts, nur dass Sie die beiden Doppelpunkte nicht schreiben. AK::foo() ist stattdessen AKFoo() . Es macht den Code 5-10% dichter und weniger langatmig, und der einzige Nachteil ist, dass Sie in große Schwierigkeiten geraten, wenn Sie zwei solche Bibliotheken verwenden müssen, die die gleiche Präfixierung haben. Beachten Sie, daß die X Window Bibliotheken in dieser Hinsicht hervorragend sind, außer daß sie vergessen haben, dies mit ein paar #defines zu tun: TRUE und FALSE hätten XTRUE und XFALSE sein müssen, und das führte zu einem Namensraumkonflikt mit Sybase oder Oracle, die ebenfalls TRUE und FALSE mit unterschiedlichen Werten verwendeten! (ASCII 0 und 1 im Falle der Datenbank!) Ein besonderer Vorteil ist, dass dies nahtlos für Präprozessor-Definitionen gilt, während die C++ using / namespace Das System kann sie nicht verarbeiten. Ein schöner Vorteil davon ist, dass es einen organischen Anstieg von einem Teil eines Projekts zu einer Bibliothek gibt. In einer großen Anwendung von mir, sind alle Fensterklassen mit dem Präfix Win , alle signalverarbeitenden Module Mod, usw. Die Wahrscheinlichkeit, dass eines dieser Module wiederverwendet wird, ist gering, so dass es keinen praktischen Nutzen hat, aus jeder Gruppe eine Bibliothek zu machen, aber es macht in wenigen Sekunden deutlich, wie das Projekt in Unterprojekte aufgeteilt ist.

1 Stimmen

Endlich, danke! Sparen Sie Zeit bei jedem Code, den Sie schreiben vs. Zeit zu "vielleicht" reparieren ein Legacy-Code zumindest mit der Standard-Bibliothek.

8voto

Engine Dev Punkte 121

Meiner Erfahrung nach, wenn Sie mehrere Bibliotheken haben, die z.B., cout aber für einen anderen Zweck verwenden Sie vielleicht die falsche cout .

Zum Beispiel, wenn ich eingebe, using namespace std; y using namespace otherlib; und tippen Sie einfach cout (die zufällig in beiden enthalten ist), anstatt std::cout (oder 'otherlib::cout' ), könnten Sie den falschen verwenden und Fehler erhalten. Es ist viel effektiver und effizienter, Folgendes zu verwenden std::cout .

8voto

Ich stimme mit anderen überein, dass es zu Namenskonflikten und Unklarheiten kommen kann und dass es weniger eindeutig ist. Ich kann zwar die Verwendung von using Ich persönlich ziehe es vor, sie zu begrenzen. Ich würde auch das in Betracht ziehen, worauf einige andere hingewiesen haben:

Wenn Sie einen Funktionsnamen suchen, der zwar recht häufig vorkommt, aber nur in der std Namespace (oder umgekehrt - Sie wollen alle Aufrufe ändern, die no im Namensraum std , Namensraum X , ...), wie wollen Sie dann vorgehen?

Sie könnten ein Programm dafür schreiben, aber wäre es nicht besser, die Zeit damit zu verbringen, an Ihrem Projekt selbst zu arbeiten, anstatt ein Programm zu schreiben, das Ihr Projekt verwaltet?

Ich persönlich habe eigentlich nichts gegen die std:: Vorwahl. Ich mag das Aussehen mehr als das Fehlen eines Präfixes. Ich weiß nicht, ob das daran liegt, dass es explizit ist und mir sagt: "Das ist nicht mein Code... Ich verwende die Standardbibliothek", oder ob es etwas anderes ist, aber ich finde, es sieht schöner aus. Das mag seltsam sein, wenn man bedenkt, dass ich mich erst seit kurzem mit C++ beschäftige (ich benutze C und andere Sprachen schon viel länger und C ist meine Lieblingssprache aller Zeiten, gleich nach Assembler).

Es gibt noch eine weitere Sache, die allerdings etwas mit dem oben Gesagten und dem, was andere gesagt haben, zu tun hat. Auch wenn es vielleicht eine schlechte Praxis ist, behalte ich mir manchmal std::name für die Version der Standardbibliothek und name für die programmspezifische Implementierung. Ja, das könnte Sie beißen und zwar heftig, aber es läuft alles darauf hinaus, dass ich dieses Projekt von Grund auf neu begonnen habe und ich der einzige Programmierer dafür bin. Beispiel: Ich überlade std::string und nennen es string . Ich habe hilfreiche Ergänzungen. Ich habe das zum Teil wegen meiner C- und Unix (+ Linux)-Tendenz zu klein geschriebenen Namen gemacht.

Außerdem können Sie Namespace-Aliase haben. Hier ist ein Beispiel dafür, wo dies nützlich ist, das vielleicht noch nicht erwähnt wurde. Ich verwende den C++11-Standard und zwar mit libstdc++. Nun, sie hat keine vollständige std::regex unterstützen. Sicher, es kompiliert, aber es wirft eine Ausnahme nach dem Muster, dass es ein Fehler auf der Seite des Programmierers ist. Aber es ist ein Mangel an Implementierung.

Ich habe das Problem folgendermaßen gelöst. Installiere Boosts Regex und binde sie ein. Dann tue ich das folgende, so dass, wenn libstdc++ es vollständig implementiert hat, ich brauche nur diesen Block zu entfernen und der Code bleibt der gleiche:

namespace std
{
    using boost::regex;
    using boost::regex_error;
    using boost::regex_replace;
    using boost::regex_search;
    using boost::regex_match;
    using boost::smatch;
    namespace regex_constants = boost::regex_constants;
}

Ich will nicht darüber streiten, ob das eine schlechte Idee ist oder nicht. Ich werde jedoch argumentieren, dass es sauber bleibt für meine Projekt und macht es gleichzeitig spezifisch: Stimmt, ich muss Boost verwenden, sondern Ich benutze es, wie die libstdc++ es schließlich haben wird. Ja, wenn man sein eigenes Projekt startet und mit einem Standard (...) ganz am Anfang beginnt, hilft das sehr bei der Wartung, Entwicklung und allem, was mit dem Projekt zu tun hat!

Nur um etwas klarzustellen: Ich halte es eigentlich nicht für eine gute Idee, den Namen einer Klasse/was auch immer in der STL absichtlich und konkret anstelle von. Der String ist die Ausnahme (ignorieren Sie das erste, obige oder zweite hier, Wortspiel, wenn es sein muss) für mich, da ich die Idee von "String" nicht mochte.

So wie es aussieht, bin ich immer noch sehr voreingenommen gegenüber C und voreingenommen gegenüber C++. Wenn man von Details absieht, passt vieles von dem, woran ich arbeite, eher zu C (aber es war eine gute Übung und ein guter Weg, um a. eine andere Sprache zu lernen und b. zu versuchen, weniger voreingenommen gegenüber Objekten/Klassen/etc. zu sein, was man vielleicht besser als weniger engstirnig, weniger arrogant und mehr akzeptierend bezeichnen könnte). Aber was ist nützlich ist, was einige bereits vorgeschlagen: Ich benutze in der Tat Liste (es ist ziemlich allgemein, nicht wahr?), und sortieren (dieselbe Sache), um zwei zu nennen, die einen Namenskonflikt verursachen würden, wenn ich tun würde using namespace std; Deshalb ziehe ich es vor, spezifisch zu sein, die Kontrolle zu haben und zu wissen, dass ich es angeben muss, wenn ich es als Standard verwenden will. Einfach ausgedrückt: Annehmen ist nicht erlaubt.

Und um Boosts Regex zu einem Teil von std . Ich tue das für die künftige Integration und - auch hier gebe ich zu, dass ich voreingenommen bin - ich denke nicht, dass es so hässlich ist wie boost::regex:: ... . Das ist in der Tat eine andere Sache für mich. Es gibt viele Dinge in C++, die ich in Bezug auf Aussehen und Methoden noch immer nicht vollständig akzeptieren kann (ein weiteres Beispiel: variadische Vorlagen gegenüber var-Argumenten [obwohl ich zugeben muss, dass variadische Vorlagen sehr nützlich sind]). Selbst bei den Dingen, die ich akzeptiere, war es schwierig, und Ich habe immer noch Probleme mit ihnen.

1 Stimmen

Ausweitung der std Namespace ist undefiniertes Verhalten und sollte daher niemals durchgeführt werden.

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