it-swarm.com.de

Warum wird der Namespace std verwendet? als schlechte Praxis?

Mir wurde von anderen gesagt, dass das Schreiben von using namespace std; im Code falsch ist und ich stattdessen std::cout und std::cin direkt verwenden sollte.

Warum wird using namespace std; als schlechte Praxis angesehen? Ist es ineffizient oder besteht die Gefahr, dass mehrdeutige Variablen deklariert werden (Variablen, die denselben Namen wie eine Funktion im std -Namensraum haben)? Beeinträchtigt es die Leistung?

2409
akbiggs

Dies hängt überhaupt nicht mit der Leistung zusammen. Beachten Sie jedoch Folgendes: Sie verwenden zwei Bibliotheken mit den Namen Foo und Bar:

using namespace foo;
using namespace bar;

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

Wenn Sie foo::Blah() und bar::Quux() verwendet hätten, wäre die Einführung von foo::Quux() kein Ereignis gewesen.

2037
Greg Hewgill

Ich bin mit allem einverstanden Greg schrieb , aber ich möchte hinzufügen: Es kann noch schlimmer werden, als Greg sagte!

Library Foo 2.0 könnte die Funktion Quux() einführen, die für einige Ihrer Aufrufe von Quux() eindeutig besser geeignet ist als die Funktion bar::Quux(), die Ihr Code seit Jahren aufgerufen hat. Dann kompiliert Ihr Code noch , aber ruft stillschweigend die falsche Funktion auf und macht Gott-weiß-was. Das ist ungefähr so ​​schlimm, wie es nur geht.

Denken Sie daran, dass der Namespace std Unmengen von Bezeichnern enthält, von denen viele sehr gebräuchlich sind (denken Sie an list, sort, string, iterator usw.), die sehr wahrscheinlich auch in anderem Code vorkommen.

Wenn Sie dies für unwahrscheinlich halten: Es gab eine gestellte Frage hier bei Stack Overflow, wo ziemlich genau dies passierte (falsche Funktion aufgerufen, weil das std:: -Präfix weggelassen wurde), ungefähr ein halbes Jahr nachdem ich dies gegeben hatte Antworten. Hier ist ein weiteres, neueres Beispiel für eine solche Frage. Das ist also ein echtes Problem.


Hier ist noch ein Datenpunkt: Vor vielen, vielen Jahren fand ich es auch ärgerlich, alles aus der Standardbibliothek mit std:: voranstellen zu müssen. Dann habe ich in einem Projekt gearbeitet, in dem zu Beginn entschieden wurde, dass sowohl using Direktiven als auch Deklarationen mit Ausnahme von Funktionsbereichen verboten sind. Erraten Sie, was? Die meisten von uns brauchten sehr wenige Wochen, um sich an das Schreiben des Präfixes zu gewöhnen, und nach einigen weiteren Wochen waren sich die meisten von uns sogar einig, dass es den Code tatsächlich lesbarer machte . Dafür gibt es einen Grund: Ob Sie kürzere oder längere Prosa mögen, ist subjektiv, aber die Präfixe verleihen dem Code objektiv Klarheit. Nicht nur der Compiler, sondern auch Sie können leichter erkennen, auf welchen Bezeichner verwiesen wird.

In einem Jahrzehnt wuchs dieses Projekt auf mehrere Millionen Codezeilen. Da diese Diskussionen immer wieder auftauchen, war ich mal gespannt, wie oft der (erlaubte) Funktionsumfang using tatsächlich im Projekt genutzt wurde. Ich habe die Quellen durchsucht und nur ein oder zwei Dutzend Stellen gefunden, an denen es verwendet wurde. Für mich bedeutet dies, dass Entwickler einmal ausprobiert std:: nicht schmerzhaft genug finden, um Anweisungen auch nur einmal alle 100 kLoC zu verwenden, selbst wenn dies zulässig war.


Fazit: Explizites Präfixieren schadet nicht, ist gewöhnungsbedürftig und hat objektive Vorteile. Insbesondere erleichtert es dem Compiler und menschlichen Lesern die Interpretation des Codes - und dies sollte wahrscheinlich das Hauptziel beim Schreiben von Code sein.

1300
sbi

Das Problem beim Einfügen von using namespace in die Header-Dateien Ihrer Klassen besteht darin, dass jeder, der Ihre Klassen verwenden möchte (indem er Ihre Header-Dateien einbezieht), gezwungen ist, auch diese anderen Namespaces zu verwenden (d. H. Alles in ihnen zu sehen).

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


Beachten Sie, dass manche Leute mit meiner Aussage "fühlen Sie sich frei" nicht einverstanden sind - denn obwohl eine using-Anweisung in einer cpp-Datei besser ist als in einer Kopfzeile ( weil es nicht die Leute betrifft, die Ihre Header-Datei enthalten), denken sie, dass es immer noch nicht gut ist (weil es abhängig vom Code die Implementierung von machen könnte die Klasse schwieriger zu pflegen). Dieses FAQ Thema sagt,

Die using-Direktive gibt es für älteren C++ - Code und zur Erleichterung des Übergangs zu Namespaces. Sie sollten sie jedoch wahrscheinlich nicht regelmäßig verwenden, zumindest nicht in Ihrem neuen C++ - Code.

Das FAQ schlägt zwei Alternativen vor:

  • Eine Verwendungserklärung:

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

    std::cout << "Values:";
    
375
ChrisW

Ich bin kürzlich auf eine Beschwerde über Visual Studio 201 gestoßen. Es stellte sich heraus, dass so ziemlich alle Quelldateien diese beiden Zeilen hatten:

using namespace std;
using namespace boost;

Viele Boost -Funktionen fließen in den C++ 0x-Standard ein, und Visual Studio 2010 verfügt über viele C++ 0x-Funktionen, sodass diese Programme plötzlich nicht mehr kompiliert wurden.

Das Vermeiden von using namespace X; ist daher eine Form der Zukunftssicherheit. Sie können also sicherstellen, dass eine Änderung an den verwendeten Bibliotheken und/oder Header-Dateien kein Programm beeinträchtigt.

225
David Thornley

Kurzversion: Verwenden Sie global keine Deklarationen oder Direktiven in Header-Dateien. Fühlen Sie sich frei, sie in Implementierungsdateien zu verwenden. Das sagen Herb Sutter und Andrei Alexandrescu zu diesem Thema in C++ Coding Standards (Hervorhebungen sind meine):

Zusammenfassung

Die Verwendung von Namespaces dient Ihrer Bequemlichkeit und ist nicht dazu gedacht, andere zu beeinflussen: Schreiben Sie niemals eine using-Deklaration oder eine using-Direktive vor einer # include-Direktive.

Folgerung: Schreiben Sie in Header-Dateien keine Namespace-Ebene mit Direktiven oder Deklarationen. Verwenden Sie stattdessen explizit den Namespace, um alle Namen zu qualifizieren. (Die zweite Regel folgt aus der ersten, da Header niemals wissen können, welche anderen Header #includes möglicherweise nach ihnen erscheinen.)

Diskussion

Kurz gesagt: Sie können und sollten Namespace verwenden, indem Sie Deklarationen und Anweisungen in Ihren Implementierungsdateien großzügig nach # include-Anweisungen einfügen, und sich dabei wohlfühlen. Trotz wiederholter gegenteiliger Behauptungen sind Namespaces, die Deklarationen und Direktiven verwenden, nicht böse und setzen den Zweck von Namespaces nicht außer Kraft. Sie sind vielmehr das, was Namespaces nutzbar macht .

203
mattnewport

Die Verwendung von Direktiven sollte nicht im globalen Bereich verwendet werden, insbesondere nicht in Kopfzeilen. Es gibt jedoch Situationen, in denen dies auch in einer Headerdatei angemessen 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 die explizite Qualifizierung (std::sin, std::cos...), da es kürzer ist und mit benutzerdefinierten Gleitkommatypen arbeiten kann (über die argumentabhängige Suche).

117
robson3.14

Verwenden Sie es nicht global

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

  • Sie überfrachten den Namespace, in dem Sie programmieren.
  • Wenn Sie viele using namespace xyz verwenden, können die Leser nur schwer erkennen, woher ein bestimmter Bezeichner stammt.
  • Was auch immer für andere Leser Ihres Quellcodes zutrifft, gilt umso mehr für den häufigsten Leser: Sie selbst. Komme in ein oder zwei Jahren wieder und schau es dir an ...
  • Wenn Sie nur über using namespace std sprechen, sind Sie sich möglicherweise nicht aller Dinge bewusst, die Sie greifen - und wenn Sie einen weiteren #include hinzufügen oder zu einer neuen C++ - Revision wechseln, können Namenskonflikte auftreten, die Ihnen nicht bekannt waren .

Sie können es lokal verwenden

Gehen Sie vor und nutzen Sie es lokal (fast) frei. Dies verhindert natürlich die Wiederholung von std:: - und die Wiederholung ist auch schlecht.

Eine Redewendung für die lokale Verwendung

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

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 den std::swap für value_, d. H. void std::swap(int, int).
  • Wenn Sie eine Überladung void swap(Child&, Child&) implementiert haben, wählt der Compiler diese aus.
  • Wenn Sie nicht über diese Überladung verfügen, verwendet der Compiler void std::swap(Child&,Child&) und versucht, diese nach besten Kräften auszutauschen.

In 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 auszuwählen.

95
towi

Wenn Sie die richtigen Header-Dateien importieren, haben Sie plötzlich Namen wie hex , left , plus oder count in Ihrer globalen Liste Umfang. Dies ist möglicherweise überraschend, wenn Sie nicht wissen, dass std:: diese Namen enthält. Wenn Sie versuchen, diese Namen auch lokal zu verwenden, kann dies zu Verwirrung führen.

Wenn sich das gesamte Standardmaterial in einem eigenen Namespace befindet, müssen Sie sich keine Gedanken über Namenskollisionen mit Ihrem Code oder anderen Bibliotheken machen.

76
sth

Erfahrene Programmierer verwenden alles, was ihre Probleme löst, und vermeiden, was neue Probleme verursacht. Genau aus diesem Grund vermeiden sie die Verwendung von Direktiven auf Header-Dateiebene.

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

Was sind das gute Gründe? Manchmal möchten Programmierer ADL explizit deaktivieren, manchmal möchten sie die Mehrdeutigkeit aufheben.

Folgendes ist also in Ordnung:

  1. Using-Direktiven und using-Deklarationen auf Funktionsebene in Funktionsimplementierungen
  2. Verwendung von Deklarationen in Quelldateien auf Quelldateiebene
  3. (Manchmal) Quelldatei-Ebene using-Direktiven
44

Ein weiterer Grund ist die Überraschung.

Wenn ich cout << blah anstelle von std::cout << blah sehe

Ich denke, was ist das cout? Ist es das normale cout? Ist es etwas besonderes

43
Martin Beckett

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 C++ - Programmiersprache":

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 Unklarheiten behoben, die sich aus ihrer Zusammensetzung ergeben.

Dort explizit deklarierte Namen (einschließlich Namen, die durch using-Deklarationen wie His_lib::String deklariert wurden) haben Vorrang vor Namen, die durch eine using-Direktive (using namespace Her_lib) in einem anderen Gültigkeitsbereich zugänglich gemacht wurden.

40
Oleksiy

Ich halte es auch für eine schlechte Praxis. Warum? Nur eines Tages dachte ich, dass die Funktion eines Namespaces darin besteht, Dinge zu teilen, damit ich es nicht damit verderben sollte, alles in eine globale Tasche zu werfen. Wenn ich jedoch häufig 'cout' und 'cin' verwende, schreibe ich: using std::cout; using std::cin; in die cpp-Datei (niemals in die Header-Datei, da sie sich mit #include verbreitet). Ich denke, dass niemand vernünftig jemals einen Stream cout oder cin nennen wird. ;)

28
Yelonek

Es ist schön, Code zu sehen und zu wissen, was er tut. Wenn ich std::cout sehe, weiß ich, dass dies der Stream cout der Bibliothek std ist. Wenn ich cout sehe, weiß ich es nicht. Es ist könnte der Stream cout der Bibliothek std. Oder es könnte int cout = 0; zehn Zeilen höher in derselben Funktion geben. Oder eine static -Variable mit dem Namen cout in dieser Datei. Es könnte alles sein.

Nehmen Sie nun eine Millionen-Zeilen-Code-Basis, die nicht besonders groß ist, und suchen Sie nach einem Fehler. Das heißt, Sie wissen, dass eine Zeile in dieser Million Zeilen nicht das tut, was sie tun sollen. cout << 1; konnte einen static int mit dem Namen cout lesen, um ein Bit nach links verschieben und das Ergebnis wegwerfen. Auf der Suche nach einem Bug müsste ich das überprüfen. Kannst du sehen, wie ich es wirklich vorziehe, std::cout zu sehen?

Es ist eines dieser Dinge, die eine wirklich gute Idee zu sein scheinen, wenn Sie Lehrer sind und nie Code schreiben und pflegen mussten, um ihren Lebensunterhalt zu verdienen. Ich mag es, Code zu sehen, wo (1) ich weiß, was er tut; und (2) ich bin zuversichtlich, dass die Person, die es schreibt, wusste, was es tut.

23
gnasher729

Es geht darum, Komplexität zu managen. Wenn Sie den Namespace verwenden, werden unerwünschte Aktionen ausgeführt, und das Debuggen wird möglicherweise erschwert (ich sage möglicherweise). Die Verwendung von std :: all over the place ist schwieriger zu lesen (mehr Text und so weiter).

Pferde für Kurse - verwalten Sie Ihre Komplexität so, wie Sie es am besten können und können.

22
Preet Sangha
  1. sie müssen in der Lage sein, Code zu lesen, der von Personen geschrieben wurde, die andere Ansichten zu Stil und Best Practices haben als Sie.

  2. Wenn Sie nur cout verwenden, wird niemand verwirrt. Aber wenn viele Namespaces herumfliegen und Sie diese Klasse sehen und nicht genau wissen, was sie tut, fungiert der explizite Namespace als eine Art Kommentar. Sie können auf den ersten Blick erkennen, dass es sich um eine Dateisystemoperation oder eine Netzwerkoperation handelt.

18
Dustin Getz

Die gleichzeitige Verwendung vieler Namespaces ist natürlich ein Rezept für eine Katastrophe, aber die Verwendung von JUST-Namespace std und nur von Namespace std ist meiner Meinung nach keine so große Sache, da eine Neudefinition nur durch Ihren eigenen Code erfolgen kann ...

Betrachten Sie sie einfach als reservierte Namen wie "int" oder "class" und das wars.

Die Leute sollten aufhören, so anal zu sein. Ihr Lehrer hatte die ganze Zeit recht. Verwenden Sie einfach EINEN Namespace. Das ist der springende Punkt, wenn Namespaces an erster Stelle stehen. Sie dürfen nicht mehrere gleichzeitig verwenden. Es sei denn, es ist dein eigenes. Eine Neudefinition findet also nicht statt.

18
user2645752

Erwägen

// myHeader.h
#include <sstream>
using namespace std;


// someoneElses.cpp/h
#include "myHeader.h"

class stringstream {  // uh oh
};

Beachten Sie, dass dies ein einfaches Beispiel ist. Wenn Sie Dateien mit 20 Includes und andere Importe haben, müssen Sie eine Menge Abhängigkeiten durchgehen, um das Problem herauszufinden. Das Schlimmste daran ist, dass in anderen Modulen je nach den Definitionen, die im Konflikt stehen, Fehler auftreten können, die nichts miteinander zu tun haben.

Es ist nicht schrecklich, aber Sie sparen sich Kopfschmerzen, wenn Sie es nicht in Header-Dateien oder im globalen Namespace verwenden. Es ist wahrscheinlich in Ordnung, dies in sehr begrenztem Umfang zu tun, aber ich hatte noch nie ein Problem, die zusätzlichen 5 Zeichen einzugeben, um zu verdeutlichen, woher meine Funktionen kommen.

18
Ron Warholic

Ein Namespace ist ein benannter Bereich. Namespaces werden verwendet, um zusammengehörige Deklarationen zu gruppieren und separate Elemente voneinander zu trennen. Beispielsweise können zwei separat entwickelte Bibliotheken denselben Namen verwenden, um auf verschiedene Elemente zu verweisen, ein Benutzer kann jedoch weiterhin beide verwenden:

namespace Mylib{
    template<class T> class Stack{ /* ... */ };
    / / ...
}
namespace Yourlib{
    class Stack{ /* ... */ };
    / / ...
}
void f(int max) {
    Mylib: :Stack<int> s1(max) ; / / use my stack
    Yourlib: :Stack s2(max) ; / / use your stack
    / / ...
}

Das Wiederholen eines Namespace-Namens kann sowohl für Leser als auch für Autoren eine Ablenkung sein. Infolgedessen kann angegeben werden, dass Namen aus einem bestimmten Namespace ohne explizite Qualifikation verfügbar sind. Zum Beispiel:

void f(int max) {
    using namespace Mylib; / / make names from Mylib accessible
    Stack<int> s1(max) ; / / use my stack
    Yourlib: :Stack s2(max) ; / / use your stack
    / / ...
}

Namespaces bieten ein leistungsstarkes Tool für die Verwaltung verschiedener Bibliotheken und verschiedener Codeversionen. Insbesondere bieten sie dem Programmierer Alternativen, wie explizit auf einen nichtlokalen Namen verwiesen werden kann.

Quelle: Ein Überblick über die Programmiersprache C++ von Bjarne Stroustrup

12
Rohan Singh

Ich stimme den anderen hier zu, möchte jedoch auf die Bedenken hinsichtlich der Lesbarkeit eingehen. Sie können all dies vermeiden, indem Sie einfach typedefs am Anfang Ihrer Datei-, Funktions- oder Klassendeklaration verwenden.

Ich verwende es normalerweise in meiner Klassendeklaration, da Methoden in einer Klasse dazu neigen, mit ähnlichen Datentypen (den Mitgliedern) umzugehen, und ein typedef ist eine Gelegenheit, einen Namen zuzuweisen, der im Kontext der Klasse von Bedeutung ist. Dies trägt tatsächlich zur Lesbarkeit der Definitionen der Klassenmethoden bei.

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

und in 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;
}
12
Carl

Ein konkretes Beispiel zur Verdeutlichung des Anliegens. Stellen Sie sich vor, Sie haben zwei Bibliotheken, foo und bar, die jeweils einen eigenen Namespace haben:

namespace foo {
    void a(float) { /* does something */ }
}

namespace bar {
    ...
}

Angenommen, Sie verwenden foo und bar in Ihrem eigenen Programm wie folgt zusammen:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

Zu diesem Zeitpunkt ist alles in Ordnung. Wenn Sie Ihr Programm ausführen, "tut es etwas". Aber später aktualisierst du die Leiste und sagst, es hat sich wie folgt geändert:

namespace bar {
    void a(float) { /* does something completely different */ }
}

Zu diesem Zeitpunkt wird ein Compilerfehler angezeigt:

using namespace foo;
using namespace bar;

void main() {
    a(42);  // error: call to 'a' is ambiguous, should be foo::a(42)
}

Sie müssen also einige Wartungsarbeiten durchführen, um zu klären, welches 'a' Sie gemeint haben (d. H. foo::a). Das ist wahrscheinlich unerwünscht, aber zum Glück ist es ziemlich einfach (fügen Sie foo:: vor allen Aufrufen von a hinzu, die der Compiler als mehrdeutig markiert).

Stellen Sie sich aber ein alternatives Szenario vor, in dem sich stattdessen der Balken wie folgt geändert hat:

namespace bar {
    void a(int) { /* does something completely different */ }
}

An diesem Punkt wird Ihr Aufruf von a(42) plötzlich an bar::a anstatt an foo::a gebunden, und anstatt "etwas" zu tun, wird "etwas völlig anderes" ausgeführt. Keine Compiler-Warnung oder so. Ihr Programm beginnt einfach stillschweigend, etwas völlig anderes zu tun als zuvor.

Wenn Sie einen Namespace verwenden, riskieren Sie ein solches Szenario, weshalb es den Leuten unangenehm ist, Namespaces zu verwenden. Je mehr Dinge sich in einem Namespace befinden, desto größer ist das Konfliktrisiko, sodass die Verwendung des Namespace std (aufgrund der Anzahl der Dinge in diesem Namespace) für die Benutzer möglicherweise noch unangenehmer ist als für andere Namespaces.

Letztendlich ist dies ein Kompromiss zwischen Beschreibbarkeit und Zuverlässigkeit/Wartbarkeit. Die Lesbarkeit kann ebenfalls berücksichtigt werden, aber ich konnte Argumente dafür erkennen. Normalerweise würde ich sagen, dass Zuverlässigkeit und Wartbarkeit wichtiger sind, aber in diesem Fall zahlen Sie ständig die Kosten für die Beschreibbarkeit für eine relativ seltene Auswirkung auf Zuverlässigkeit und Wartbarkeit. Der „beste“ Kompromiss bestimmt Ihr Projekt und Ihre Prioritäten.

11
Kevin

Ein Beispiel, bei dem die Verwendung des Namespace std einen Kompilierungsfehler verursacht, da die Anzahl nicht eindeutig ist. Dies ist auch eine Funktion in der Algorithmusbibliothek.

#include <iostream>

using namespace std;

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

Ich denke nicht, dass es unter allen Umständen unbedingt eine schlechte Übung ist, aber Sie müssen vorsichtig sein, wenn Sie sie verwenden. Wenn Sie eine Bibliothek schreiben, sollten Sie wahrscheinlich die Operatoren für die Bereichsauflösung mit dem Namespace verwenden, um zu verhindern, dass Ihre Bibliothek mit anderen Bibliotheken in Kontakt kommt. Bei Code auf Anwendungsebene sehe ich keine Fehler.

8
Dr. Watson

Die Leistung Ihrer Software oder Ihres Projekts wird dadurch nicht beeinträchtigt. Die Angabe des Namespaces am Anfang Ihres Quellcodes ist nicht schlecht. Die Einbeziehung der Anweisung using namespace std richtet sich nach Ihren Anforderungen und der Art und Weise, in der Sie die Software oder das Projekt entwickeln.

Der namespace std enthält die C++ - Standardfunktionen und -variablen. Dieser Namespace ist nützlich, wenn Sie häufig die C++ - Standardfunktionen verwenden.

Wie in diesem Seite erwähnt:

Die Anweisung mit dem Namespace std wird im Allgemeinen als fehlerhaft angesehen. Die Alternative zu dieser Anweisung besteht darin, den Namespace, zu dem der Bezeichner gehört, mit dem Bereichsoperator (: :) jedes Mal anzugeben, wenn wir einen Typ deklarieren.

Und siehe diese Meinung :

Es ist kein Problem, "using namespace std" in Ihrer Quelldatei zu verwenden, wenn Sie den Namespace intensiv nutzen und sicher sind, dass nichts kollidieren wird.

Einige Leute hatten gesagt, dass es eine schlechte Praxis ist, den using namespace std in Ihre Quelldateien aufzunehmen, da Sie alle Funktionen und Variablen aus diesem Namespace aufrufen. Wenn Sie eine neue Funktion mit demselben Namen wie eine andere in namespace std enthaltene Funktion definieren möchten, würden Sie die Funktion überladen und es könnten Probleme aufgrund des Kompilierens oder Ausführens auftreten. Es wird nicht wie erwartet kompiliert oder ausgeführt.

Wie in diesem Seite erwähnt:

Die Anweisung erspart uns zwar die Eingabe von std ::, wenn wir auf eine im std-Namespace definierte Klasse oder einen Typ zugreifen möchten, importiert jedoch den gesamten std-Namespace in den aktuellen Namespace des Programms. Lassen Sie uns anhand einiger Beispiele verstehen, warum dies möglicherweise nicht so gut ist

...

Zu einem späteren Zeitpunkt der Entwicklung möchten wir eine andere Version von cout verwenden, die benutzerdefiniert in einer Bibliothek namens "foo" implementiert ist (zum Beispiel).

...

Beachten Sie, wie es eine Mehrdeutigkeit gibt, auf welche Bibliothek verweist Cout? Der Compiler erkennt dies möglicherweise und kompiliert das Programm nicht. Im schlimmsten Fall kompiliert das Programm möglicherweise immer noch, ruft jedoch die falsche Funktion auf, da wir nie angegeben haben, zu welchem ​​Namespace der Bezeichner gehört.

7
CryogenicNeo

Ich stimme anderen zu - es fragt nach Namenskonflikten, Zweideutigkeiten und dann ist die Tatsache, dass es weniger explizit ist. Obwohl ich die Verwendung von using sehen kann, ist es meine persönliche Präferenz, diese zu begrenzen. Ich würde auch stark darüber nachdenken, worauf einige andere hingewiesen haben:

Wenn Sie einen Funktionsnamen suchen möchten, der möglicherweise recht gebräuchlich ist, der jedoch nur im Namespace std enthalten sein soll (oder umgekehrt: Sie möchten alle Aufrufe ändern, die NICHT im Namespace std, Namespace X, ... enthalten sind. .), wie schlagen Sie dies dann vor? Sie könnten ein Programm schreiben, um dies zu tun, aber wäre es nicht besser, Zeit damit zu verbringen, an Ihrem Projekt selbst zu arbeiten, als ein Programm zu schreiben, um Ihr Projekt zu warten?

Persönlich stört mich das std:: -Präfix eigentlich nicht. Ich mag das Aussehen mehr als es nicht zu haben. Ich weiß nicht, ob das daran liegt, dass es explizit ist und zu mir sagt, dass "dies nicht mein Code ist ... ich verwende die Standardbibliothek" oder ob es etwas anderes ist, aber ich denke, dass es schöner aussieht. Dies mag seltsam sein, da ich erst kürzlich in C++ eingestiegen bin (C und andere Sprachen werden noch viel länger verwendet und C ist meine Lieblingssprache aller Zeiten, direkt über Assembly).

Es gibt noch eine andere Sache, obwohl sie in gewisser Weise mit der obigen zusammenhängt und worauf andere hinweisen. Während dies eine schlechte Praxis sein kann, reserviere ich manchmal std::name für die Standard-Bibliotheksversion und den Namen für die programmspezifische Implementierung. Ja, das könnte dich beißen und dich hart beißen, aber es kommt darauf an, dass ich dieses Projekt von Grund auf neu gestartet habe und der einzige Programmierer dafür bin. Beispiel: Ich überlade std::string und nenne es string. Ich habe hilfreiche Ergänzungen. Ich tat es zum Teil, weil ich unter C und Unix (+ Linux) dazu neigte, Kleinbuchstaben zu verwenden.

Außerdem können Sie Namespace-Aliase haben. Hier ist ein Beispiel, wo es nützlich ist, auf das möglicherweise nicht verwiesen wurde. Ich benutze den C++ 11 Standard und speziell mit libstdc ++. Nun, es hat keine vollständige std::regex -Unterstützung. Sicher kompiliert es, aber es wirft eine Ausnahme in der Richtung auf, dass es ein Fehler am Ende des Programmierers ist. Aber es fehlt die Umsetzung. Also hier ist, wie ich es gelöst habe. Installieren Sie Boost's Regex und binden Sie es ein. Dann mache ich Folgendes, damit ich, wenn libstdc ++ es vollständig implementiert hat, nur diesen Block entfernen muss und der Code der gleiche bleibt:

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 werde nicht darüber streiten, ob das eine schlechte Idee ist oder nicht. Ich werde jedoch argumentieren, dass es für MEIN Projekt sauber bleibt und es gleichzeitig spezifisch macht: Richtig, ich muss Boost verwenden, ABER ich verwende es so, wie es die libstdc ++ irgendwann haben wird. Ja, ein eigenes Projekt zu starten und mit einem Standard (...) am Anfang zu beginnen, ist ein sehr langer Weg, um Wartung, Entwicklung und alles, was mit dem Projekt zu tun hat, zu unterstützen!

Bearbeiten:
Jetzt, da ich Zeit habe, nur um etwas zu klären. Ich halte es eigentlich nicht für eine gute Idee, einen Namen einer Klasse/was auch immer in der STL absichtlich und spezifischer anstelle von zu verwenden. Die Zeichenfolge ist die Ausnahme (ignorieren Sie die erste, obige oder zweite, Wortspiel, wenn Sie müssen), da mir die Idee von 'Zeichenfolge' nicht gefallen hat. So wie es ist, bin ich immer noch sehr voreingenommen in Richtung C und voreingenommen in Richtung C++. Sparsame Details, vieles, woran ich arbeite, passt besser zu C (aber es war eine gute Übung und ein guter Weg, um mich dazu zu bringen, eine andere Sprache zu lernen und nicht weniger voreingenommen gegenüber Objekten/Klassen/usw. zu sein, was vielleicht besser gesagt wird als weniger aufgeschlossen, weniger arrogant, mehr akzeptierend.). Aber was IS nützlich ist, was einige bereits vorgeschlagen haben: Ich verwende in der Tat list (es ist ziemlich allgemein, nicht wahr?), Sortiere (dasselbe), um zwei zu benennen, die einen Namenskonflikt verursachen würden, wenn ich es wäre um using namespace std; zu tun, bevorzuge ich es, spezifisch zu sein, die Kontrolle zu behalten und zu wissen, dass ich es spezifizieren muss, wenn ich beabsichtige, es als Standard zu verwenden. Einfach gesagt: keine Annahme erlaubt.

Und was Boosts Regex zu einem Teil von std macht. Ich mache das für die zukünftige Integration und - ich gebe zu, das ist Voreingenommenheit - ich finde es nicht so hässlich wie boost::regex:: ... In der Tat ist das eine andere Sache für mich. Es gibt viele Dinge in C++, die ich noch nicht vollständig in Aussehen und Methoden akzeptiert habe (ein weiteres Beispiel: Variadic Templates versus Var Args [obwohl ich zugebe, dass Variadic Templates sehr, sehr nützlich sind!]). Sogar die, die ich akzeptiere, waren schwierig UND ich habe immer noch Probleme mit ihnen.

6
user4138451

Bei nicht qualifizierten importierten Bezeichnern benötigen Sie externe Suchwerkzeuge wie grep, um herauszufinden, wo Bezeichner deklariert sind. Dies erschwert das Nachdenken über die Programmkorrektheit.

6

Dies ist eine schlechte Praxis, die häufig als globale Namespace-Verschmutzung bezeichnet wird. Probleme können auftreten, wenn mehr als ein Namespace denselben Funktionsnamen mit Signatur hat. Dann kann der Compiler nicht eindeutig entscheiden, welcher Namespace aufgerufen werden soll. Dies alles kann vermieden werden, wenn Sie den Namespace mit Ihrem Funktionsaufruf wie std::cout angeben. Hoffe das hilft. :)

6
adn.911

Es hängt davon ab, wo es sich befindet. Wenn es sich um einen allgemeinen Header handelt, verringern Sie den Wert des Namespaces, indem Sie ihn in den globalen Namespace zusammenführen. Denken Sie daran, dies könnte eine gute Möglichkeit sein, Modul-Globals zu erstellen.

6
MathGladiator

"Warum wird der Namespace std verwendet?" als eine schlechte Praxis in C++? "

Ich sage es anders herum: Warum wird die Eingabe von 5 zusätzlichen Zeichen von manchen als umständlich empfunden?

Betrachten Sie z.B. Warum sollte ich beim Schreiben einer numerischen Software überhaupt in Betracht ziehen, meinen globalen Namespace durch Reduzieren von "std :: vector" auf "vector" zu verschmutzen, wenn "vector" eines der wichtigsten Konzepte der Problemdomäne ist?

6
Solkar

Um Ihre Frage zu beantworten, sehe ich das praktisch so: Viele Programmierer (nicht alle) rufen den Namespace std auf. Daher sollte man es sich zur Gewohnheit machen, KEINE Dinge zu verwenden, die die gleichen Namen haben oder verwenden wie das, was im Namespace std steht. Das ist eine große Selbstverständlichkeit, aber nicht so sehr im Vergleich zu der Anzahl möglicher zusammenhängender Wörter und Pseudonyme, die genau genommen gefunden werden können.

Ich meine wirklich ... wenn du sagst "Verlass dich nicht darauf, dass es da ist", dann bist du nur bereit, dich darauf zu verlassen, dass es NICHT da ist. Sie werden ständig Probleme haben, Code-Schnipsel auszuleihen und sie ständig zu reparieren. Halten Sie einfach Ihre benutzerdefinierten und ausgeliehenen Inhalte in einem begrenzten Umfang, wie sie sein sollten, und gehen Sie dabei sehr sparsam mit Globals um (ehrlich gesagt sollten Globals fast immer das letzte Mittel sein, um "Jetzt kompilieren, später vernünftig" zu sein). Wirklich denke ich, dass es ein schlechter Rat von Ihrem Lehrer ist, weil die Verwendung von std sowohl für "cout" als auch für "std :: cout" funktioniert, aber NICHT die Verwendung von std funktioniert nur für "std :: cout". Sie werden nicht immer das Glück haben, Ihren gesamten Code selbst zu schreiben.

HINWEIS: Konzentrieren Sie sich nicht zu sehr auf Effizienzprobleme, bis Sie tatsächlich ein wenig über die Funktionsweise von Compilern erfahren. Mit ein wenig Erfahrung im Codieren müssen Sie nicht so viel über sie lernen, bevor Sie erkennen, wie viel sie in der Lage sind, guten Code in etwas Einfaches zu verallgemeinern. Genauso einfach, als ob Sie das Ganze in C geschrieben hätten. Guter Code ist nur so komplex, wie er sein muss.

5
Noneyo Getit

Wenn Sie über mehrere Bibliotheken verfügen, die beispielsweise cout verwenden, können Sie meiner Erfahrung nach für einen anderen Zweck das falsche cout verwenden.

Wenn ich zum Beispiel using namespace std; und using namespace otherlib; eingebe und nur cout (was zufällig in beiden ist) anstelle von std::cout (oder 'otherlib::cout') eingebe, könnten Sie das Verwenden Sie den falschen und erhalten Sie Fehler. Es ist viel effektiver und effizienter, std::cout zu verwenden.

5
Engine Dev

Ja, der Namespace ist wichtig. Einmal in meinem Projekt musste ich eine var-Deklaration in meinen Quellcode importieren, aber beim Kompilieren kam es zu Konflikten mit einer anderen Bibliothek von Drittanbietern.

Am Ende musste ich es auf andere Weise umgehen und den Code weniger klar machen.

4
harris

Ich denke, die Verwendung von lokal oder global sollte von der Anwendung abhängen.

Denn wenn wir die Bibliothek lokal verwenden, wird Code manchmal ein echtes Durcheinander. Die Lesbarkeit ist zu gering.

daher sollten wir Bibliotheken lokal verwenden, wenn nur die Möglichkeit von Konflikten besteht.

Ich bin keine erfahrene Person mehr. Also lass es mich wissen, wenn ich falsch liege.

2
meupul

Das folgende Beispiel zeigt, wie using namespace std; zu Problemen mit Namenskonflikten führen kann:

Eine globale Variable kann in c ++ nicht definiert werden

Im Beispiel stößt ein sehr allgemeiner Algorithmusname (std::count) mit einem sehr vernünftigen Variablennamen (count) zusammen.

2
Martin G

Um ehrlich zu sein, ist das für mich so, als würde man die Anzahl der Einrückungsbereiche diskutieren. Die Verwendung von Anweisungen in Kopfzeilen führt zu Schäden. Aber in C++ - Dateien? Möglicherweise, wenn Sie zwei Namespaces gleichzeitig verwenden. Wenn Sie jedoch eines verwenden, geht es eher um Stil als um echte Effizienz. Wissen Sie, warum Themen zum Thema Einrückung so beliebt sind? Jeder kann etwas dazu sagen und klingt sehr schlau und erfahren.

1
Timon Paßlick

Es ist von Fall zu Fall. Wir möchten die "Total Cost of Ownership" der Software über ihre Lebensdauer minimieren. Die Angabe von "using namespace std" hat einige Kosten, aber die nicht Verwendung hat auch Kosten in der Lesbarkeit.

Zu Recht wird darauf hingewiesen, dass Ihr Code bei der Verwendung der Standardbibliothek, wenn neue Symbole und Definitionen eingeführt werden, nicht mehr kompiliert wird und Sie möglicherweise gezwungen sind, Variablen umzubenennen. Und dies ist auf lange Sicht wahrscheinlich gut, da zukünftige Betreuer vorübergehend verwirrt oder abgelenkt sind, wenn Sie ein Keyword für einen überraschenden Zweck verwenden. Sie möchten nicht , dass eine Vorlage mit dem Namen "Vektor" erstellt wird. Dieser Vektor ist beispielsweise nicht allen anderen bekannt. Und die Anzahl der neuen Definitionen, die auf diese Weise in die C++ - Bibliothek eingeführt werden, ist so gering, dass sie möglicherweise einfach nicht verfügbar sind. Es gibt Kosten, um diese Art von Änderung vornehmen zu müssen, aber die Kosten sind nicht hoch und werden durch die Klarheit ausgeglichen, die durch die Nichtverwendung von Standard-Symbolnamen erzielt wird für andere Zwecke.

Angesichts der Anzahl der Klassen, Variablen und Funktionen kann die Angabe von std :: on every Ihren Code um 50% auflockern und es schwieriger machen, sich zurechtzufinden. Ein Algorithmus oder ein Schritt in einer Methode, der auf einem Bildschirm voll Code ausgeführt werden könnte, erfordert jetzt einen Bildlauf vor und zurück, um zu folgen. Das sind echte Kosten. Möglicherweise sind die Kosten nicht hoch, aber Menschen, die dies leugnen, sind unerfahren, dogmatisch oder einfach falsch.

Ich würde die folgenden Regeln anbieten:

  1. std unterscheidet sich von allen anderen Bibliotheken. Es ist die einzige Bibliothek, die jeder grundsätzlich kennen muss, und meiner Ansicht nach ist sie am besten als Teil der Sprache zu verstehen. Im Allgemeinen gibt es einen ausgezeichneten Fall für using namespace std, auch wenn es keinen für andere Bibliotheken gibt.

  2. Erzwingen Sie die Entscheidung niemals dem Autor einer Zusammenstellungseinheit (einer CPP-Datei), indem Sie diese in einen Header einfügen. Immer die Entscheidung auf den Verfasser der Zusammenstellungseinheit verschieben. Selbst in einem Projekt, das sich dafür entschieden hat, using namespace std überall zu verwenden, können einige Module, die am besten als Ausnahmen von dieser Regel behandelt werden, in Ordnung gebracht werden.

  3. Obwohl mit der Namespace-Funktion viele Module mit identischen Symbolen definiert werden können, ist dies verwirrend. Halten Sie die Namen so weit wie möglich unterschiedlich. Selbst wenn Sie die Namespace-Funktion nicht verwenden, ist es wahrscheinlich besser, Ihre Klasse langfristig umzubenennen, wenn Sie eine Klasse mit dem Namen foo haben und std eine Klasse mit dem Namen foo einführt.

  4. Eine Alternative zur Verwendung von Namespaces besteht darin, Namespacesymbole manuell mit einem Präfix zu versehen. Ich habe zwei Bibliotheken, die ich seit Jahrzehnten benutze, beide beginnend als C-Bibliotheken, wobei jedem Symbol das Präfix "AK" oder "SCWin" vorangestellt ist. . Im Allgemeinen ist dies wie das Vermeiden des "using" -Konstrukts, aber Sie schreiben nicht die Doppelpunkte. AK :: foo () ist stattdessen AKFoo (). Dadurch wird der Code 5-10% dichter und weniger ausführlich, und der einzige Nachteil ist, dass Sie große Probleme haben, wenn Sie zwei solcher Bibliotheken mit dem gleichen Präfix verwenden müssen. Beachten Sie, dass die X-Windows-Bibliotheken in dieser Hinsicht ausgezeichnet sind, außer dass sie dies mit ein paar #defines vergessen haben: TRUE und FALSE sollten XTRUE und XFALSE gewesen sein, und dies richtete einen Namespace-Konflikt mit Sybase oder Oracle ein, die ebenfalls TRUE und verwendeten FALSE mit unterschiedlichen Werten! (ASCII 0 und 1 bei der Datenbank!) Ein besonderer Vorteil hierbei ist, dass es sich nahtlos auf Präprozessordefinitionen bezieht, während das C++ using/namespace-System diese nicht verarbeitet. Ein netter Vorteil davon ist, dass es eine organische Steigung von einem Teil eines Projekts zu einer Bibliothek gibt. In einer großen Anwendung von mir werden allen Fensterklassen Win, allen Signalverarbeitungsmodulen Mod usw. vorangestellt. Es gibt nur eine geringe Chance, dass diese wiederverwendet werden, sodass es keinen praktischen Nutzen bringt, jede Gruppe in eine Bibliothek zu verwandeln, aber es wird in wenigen Sekunden deutlich, wie das Projekt in Unterprojekte unterteilt wird.

1
Swiss Frank

Hier ist ein Standpunkt, den ich in keiner der anderen Antworten gefunden habe: Verwenden Sie nur einen Namespace. Der Hauptgrund, warum Namespaces laut den meisten Antworten schlecht sind, besteht darin, dass Sie möglicherweise widersprüchliche Funktionsnamen haben, was zu einem Total Chaos führen kann. Dies tritt jedoch nicht auf, wenn Sie nur einen Namespace verwenden. Entscheiden Sie, welche Bibliothek Sie am häufigsten verwenden (vielleicht using namespace std;), und bleiben Sie dabei.

Man kann sich vorstellen, dass es ein unsichtbares Bibliothekspräfix gibt - std::vector wird nur vector. Meiner Meinung nach ist dies das Beste aus beiden Welten: Einerseits wird der Aufwand für die Eingabe reduziert (wie von Namespaces beabsichtigt), und andererseits müssen Sie die Präfixe aus Gründen der Klarheit und Sicherheit weiterhin verwenden. Wenn es eine Funktion oder ein Objekt ohne Namespace-Präfix gibt, wissen Sie, dass es sich um den von Ihnen angegebenen Namespace handelt.

Denken Sie daran, dass Sie, wenn Sie sich für eine globale Verwendung entscheiden, andere nicht lokal verwenden. Dies kehrt zu den anderen Antworten zurück, dass lokale Namespaces häufig nützlicher sind als globale, da sie Abwechslung bieten.

1
m_highlanderish