it-swarm.com.de

Was ist "Verschmutzung durch Namespace"?

Ich habe mir den Google Coding Guide angesehen [hier] und sie empfehlen nicht, den using namespace Oder namespace::function Zu verwenden - wenn ich ihn nicht falsch interpretiert habe.

Gilt das auch für std? cout<< Funktioniert nicht ohne. Dieses Buch empfiehlt dasselbe. Wie verwende ich cout<< Ohne using namespace std; Oder std::cout<<?

Was ist der empfohlene Weg? std::cout<<? Die meisten C++ - Lehrbücher lehren Anfänger mit using namespace std;. Verbreiten sie schlechte Codierungspraktiken?

15
Lord Loh.

Während ich den Google-Standard lese, können Sie die using namespace foo; - Direktive nirgendwo verwenden. Diese Anweisung bringt alles ein, was im Namespace deklariert ist, und ist eine häufige Ursache für Kollisionen und unerwartetes Verhalten. Andere haben eine sehr häufige zitiert: Sie haben irgendwo Ihre eigene Max- oder Min-Methode und sie kollidiert in einer src-Datei, in der jemand einen Header mit Ihrer Methode enthält und dann using namespace std; Sagt.

An bestimmten Stellen ist eine Verwendungserklärung zulässig, die die Form using ::foo::bar; Hat.

Die Leute setzen gerne Direktiven in ihren Code ein, weil dies viel Tipparbeit spart, aber mit Risiken verbunden ist. Wenn Sie eine Datei mit vielen cout-Anweisungen haben, kann ich verstehen, dass Sie nicht hundertmal std :: cout eingeben müssen, aber Sie können einfach sagen, dass Sie :: std :: cout verwenden. Ich behandle diese wie Variablendeklarationen: Setzen Sie sie dort ein, wo sie benötigt werden. Wenn eine Funktion in einer Datei mit 10 Dateien eine Ausgabe schreiben muss, deklarieren Sie den cout-Weg nicht oben, sondern fügen Sie ihn in die Funktion ein, die die eigentliche Ausgabe ausführt.

#include <ostream>
//using namespace std; // NO!
//using ::std::cout;   // less bad than using namespace, but I prefer to scope it

int main(int argc, char** argv)
{
   int rc = do_some_stuff(argc, argv);
   using ::std::endl;
   if (rc) { // print the success report
      using ::std::cout;
      cout << "The test run completed. The return code was " << rc << '.' << endl;
    } else {
      using ::std::cerr;
      cerr << "Unable to complete the test run." << endl;
    }
    return 0 == rc;
}

Das ist ein wenig extrem, da nur ein paar Zeilen ausgegeben werden, aber Sie haben die Idee.

Eine andere Sache, die man tun kann, ist Alias ​​oder typedef, um die Eingabe zu minimieren. Ich finde std :: was auch immer nicht so schlimm, aber wir haben eine riesige Menge an Quellen mit mehreren Dutzend Modulen und manchmal müssen wir Code wie console_gui::command_window::append("text") schreiben. Das wird nach einer Weile langweilig und verursacht viele lange Schlangen. Ich bin alles für so etwas

typedef console_gui::command_window cw;
cw::append("text");

solange die Aliase in einem lokalen Bereich ausgeführt werden und genügend Kontext vorhanden ist, um den Code lesbar zu machen.

18
Michael Mathews

Dies liegt daran, dass: 1) der gesamte Zweck von Namespaces, nämlich die Reduzierung von Namenskollisionen, zunichte gemacht wird; 2) Es stellt dem globalen Namespace den gesamten Namespace zur Verfügung, der mit der using-Direktive angegeben wurde.

Wenn Sie beispielsweise Ihre eigene Funktion max () einschließen und definieren, kollidiert diese mit std :: max ().

http://en.cppreference.com/w/cpp/algorithm/max

Bevorzugt wird std :: member_you_wish_to_use verwendet, da explizit angegeben wird, welcher Namespace verwendet werden soll.

8
ApplePie

Zitieren des von Ihnen angegebenen Links:

Sie können eine using-Deklaration an einer beliebigen Stelle in einer .cc-Datei sowie in Funktionen, Methoden oder Klassen in .h-Dateien verwenden.

// OK in .cc-Dateien.

// Muss sich in einer Funktion, Methode oder Klasse in .h-Dateien befinden.

using :: foo :: bar;

Der Google-Stil verbietet das Importieren von Namespaces im globalen Kontext, erlaubt dies jedoch in lokalen.

Überall dort, wo die Verwendung der Deklaration nur einen begrenzten und deutlich sichtbaren Teil des Codes betrifft, ist dies durchaus akzeptabel.

Wenn Sie den globalen Kontext verschmutzen, ist nicht verwandter Code betroffen (durch implizite Verwendung Ihres Headers). Wenn Sie dies im lokalen Kontext tun, passiert nichts.

6
Basilevs

Obwohl die Frage bereits nützliche Antworten hat, scheint ein Detail zu kurz zu sein.

Die meisten Programmierer sind zunächst etwas verwirrt mit dem Schlüsselwort using und den Beschreibungen der Verwendung von namespace, auch wenn sie versuchen, dies durch Nachschlagen der Referenz zu lernen, weil declaration und Direktive liest sich etwas äquivalent, beide sind relativ abstrakte lange Wörter, die mit d beginnen .

Auf Bezeichner in Namespaces kann zugegriffen werden, indem der Namespace explizit benannt wird:

myNamespace::myIdent

dies können viel mehr Schlüssel zum Eingeben sein. Es kann aber auch die Bedeutung Ihres Codes verringern, wenn die meisten Bezeichner auf die gleiche Weise vorangestellt werden. Das Schlüsselwort using hilft, diese Nachteile des Namespace zu vermeiden. Da using auf Compilerebene funktioniert (es ist kein Makro), bleibt seine Wirkung für den gesamten Bereich erhalten, in dem es verwendet wird. Aus diesem Grund beschränkt der Google-Stil seine Verwendung auf genau definierte Bereiche, dh Klassen in Header-Dateien oder Funktionen in CPP-Dateien.

... natürlich gibt es einen Unterschied zwischen der Deklaration

using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent

und unter Verwendung der Direktive

using myNamespace; // make all identifiers of myNamespace directly accessible

Letzteres führt bei Verwendung in großen Bereichen zu viel mehr Verwirrung.

1
Wolf

sie empfehlen nicht, den using-Namespace ornamespace: function` zu verwenden - wenn ich ihn nicht falsch interpretiert habe.

Du machtest. Die Nichtempfehlung gilt nur für die using namespace - Direktive (die allgemein als abusing namespace Bezeichnet wird, nicht ganz humorvoll). Es wird dringend empfohlen, den vollständig qualifizierten Namen einer Funktion oder eines Objekts zu verwenden, z. B. std::cout.

1
H2CO3

Bitte schön:

#include <iostream>

int main()
{
    std::endl(std::operator<<(std::cout, "Hello world!"));
}

Indem wir es auf diese Weise schreiben, vermeiden wir fehleranfällige ADL sowie die Verwendung von Anweisungen und Deklarationen.

Dies soll eine sarkastische Antwort sein. :-D

Ich bin mit Herb Sutter über Google in diesem Fall. Aus C++ - Codierungsstandards:

Sie können und sollten Namespace mit Deklarationen nd Direktiven großzügig in Ihren Implementierungsdateien nach # include-Direktiven verwenden und sich dabei wohl fühlen. Trotz wiederholter gegenteiliger Behauptungen ist der Namespace, der Deklarationen und Anweisungen verwendet, nicht böse und macht den Zweck von Namespaces nicht zunichte. Sie machen vielmehr Namespaces verwendbar.

Sie können von potenziellen Namespace-Konflikten besessen sein, die sich wahrscheinlich nie manifestieren und in einem solch astronomisch seltenen Ereignis wahrscheinlich nicht schwer zu beheben sind, indem Sie die Anweisungen using sorgfältig vermeiden und alles, was Sie verwenden, explizit angeben (bis auf die Operatoren) mit using Deklarationen, oder starten Sie einfach using namespace std. Letzteres empfehle ich aus Sicht der Produktivität.

Die meisten C++ - Lehrbücher vermitteln Anfängern die Verwendung des Namespace std. Propagieren sie schlechte Codierungspraktiken?

Das Gegenteil, wenn Sie mich fragen, und ich glaube, dass Sutter oben zustimmt.

Jetzt habe ich im Laufe meiner Karriere insgesamt etwa 3 Namespace-Konflikte als direkte Folge von using -Direktiven in Codebasen festgestellt, die sich über mehrere zehn Millionen LOC erstrecken. In allen drei Fällen befanden sie sich jedoch in Quelldateien, die sich über mehr als 50.000 Zeilen Legacy-Code erstreckten, ursprünglich in C geschrieben und dann in C++ bastardisiert wurden. Dabei wurde eine umfangreiche eklektische Liste unterschiedlicher Funktionen ausgeführt, einschließlich Headern aus einem Dutzend verschiedener Bibliotheken eine epische Liste von #includes, die sich über eine Seite erstreckt. Trotz des epischen Durcheinanders waren sie nicht allzu schwer zu beheben, da sie Build-Fehler unter OSX (dem einen Betriebssystem, auf dem der Code nicht erstellt werden konnte) und keine Laufzeitfehler verursachten. Organisieren Sie Ihren Code nicht auf diese albtraumhafte Weise, und es sollte Ihnen gut gehen.

Vermeiden Sie jedoch beideusing Anweisungen und Deklarationen in Header-Dateien. Das ist einfach nur verzögert. Aber für Quelldateien und insbesondere für solche, bei denen nicht eine ganze Seite mit #include - Anweisungen gefüllt ist, würde ich sagen, schwitzen Sie nicht, wenn Sie nicht für Google arbeiten.

1
user204677