Warum wird "Namespace std verwenden"; als schlechte Praxis angesehen?

Sep 21 2009

Ich habe von anderen gesagt , dass das Schreiben using namespace std;in Code falsch ist, und dass ich verwenden sollte std::coutund std::cinstattdessen direkt.

Warum wird dies 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 stdNamespace haben)? Beeinträchtigt es die Leistung?

Antworten

2351 GregHewgill Sep 21 2009 at 10:13

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 gut und Sie können problemlos Blah()von Foo und Quux()Bar anrufen . Aber eines Tages aktualisieren Sie auf eine neue Version von Foo 2.0, die jetzt eine Funktion namens bietet Quux(). Jetzt haben Sie einen Konflikt: Sowohl Foo 2.0 als auch Bar werden Quux()in Ihren globalen Namespace importiert . Die Behebung dieses Problems erfordert einige Anstrengungen, insbesondere wenn die Funktionsparameter übereinstimmen.

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

1442 sbi Sep 21 2009 at 16:26

Ich bin mit allem einverstanden, was Greg geschrieben hat , aber ich möchte hinzufügen: Es kann noch schlimmer werden, als Greg gesagt hat!

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

Beachten Sie, dass der stdNamespace - Tonnen - Kennungen hat, von denen viele sehr gewöhnlichsten (denken list, sort, string, iteratoretc.) , die sehr wahrscheinlich in anderen Code erscheinen, zu.

Wenn Sie dies für unwahrscheinlich halten: Hier auf Stack Overflow wurde eine Frage gestellt, bei der genau std::ein halbes Jahr nach der Beantwortung dieser Frage ziemlich genau dies geschah (falsche Funktion wurde aufgrund des ausgelassenen Präfixes aufgerufen ). Hier ist ein weiteres, neueres Beispiel für eine solche Frage. Das ist also ein echtes Problem.


Hier noch ein Datenpunkt: Vor vielen, vielen Jahren fand ich es auch ärgerlich, alles aus der Standardbibliothek voranstellen zu müssen std::. Dann habe ich in einem Projekt gearbeitet, in dem zu Beginn entschieden wurde, dass sowohl usingDirektiven 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 sogar einig, dass der Code dadurch besser lesbar wurde . 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 einmal gespannt, wie oft der (erlaubte) Funktionsumfang usingtatsächlich im Projekt verwendet wurde. Ich suchte nach den Quellen dafür und fand nur ein oder zwei Dutzend Stellen, an denen es verwendet wurde. Für mich bedeutet dies, dass Entwickler nach dem Versuch nicht std::schmerzhaft genug sind, um Direktiven auch nur einmal alle 100 kLoC zu verwenden, selbst wenn sie verwendet werden durften.


Fazit: Das explizite Präfixieren von allem schadet nicht, ist sehr gewöhnungsbedürftig und hat objektive Vorteile. Insbesondere erleichtert dies die Interpretation des Codes durch den Compiler und durch menschliche Leser - und dies sollte wahrscheinlich das Hauptziel beim Schreiben von Code sein.

453 ChrisW Sep 21 2009 at 10:22

Das Problem beim Einfügen using namespaceder Header-Dateien Ihrer Klassen besteht darin, dass jeder, der Ihre Klassen verwenden möchte (indem er Ihre Header-Dateien einbezieht), auch diese anderen Namespaces "verwendet" (dh alles darin sieht).

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


Beachten Sie, dass einige Leute mit meinem Sprichwort "Fühlen Sie sich frei" nicht einverstanden sind - denn obwohl eine usingAussage in einer CPP-Datei besser ist als in einem Header (weil sie keine Auswirkungen auf Personen hat, die Ihre Header-Datei enthalten), denken sie, dass dies immer noch nicht der Fall ist gut (weil es je nach Code die Wartung der Klasse schwieriger machen könnte). Dieser C ++ Super-FAQ-Eintrag sagt:

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

Die FAQ schlägt zwei Alternativen vor:

  • Eine using-Erklärung:

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

    std::cout << "Values:";
    
241 DavidThornley Oct 29 2010 at 00:37

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

using namespace std;
using namespace boost;

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

Vermeiden using namespace X;ist daher eine Form der Zukunftssicherheit, um sicherzustellen, dass eine Änderung der verwendeten Bibliotheken und / oder Header-Dateien ein Programm nicht beschädigt.

216 mattnewport Nov 04 2014 at 03:00

Kurzversion: Verwenden Sie keine globalen usingDeklarationen oder Anweisungen in Header-Dateien. Fühlen Sie sich frei, sie in Implementierungsdateien zu verwenden. Hier ist, was Herb Sutter und Andrei Alexandrescu zu diesem Problem in C ++ Coding Standards zu sagen haben (Fettdruck für die Betonung liegt bei mir):

Zusammenfassung

Namespace-Verwendungen dienen Ihrer Bequemlichkeit und nicht anderen, die Sie anderen zufügen möchten: 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. Stattdessen qualifizieren Sie alle Namen explizit für den Namespace. (Die zweite Regel folgt aus der ersten, da Header nie wissen können, welche anderen Header #includes nach ihnen erscheinen könnten.)

Diskussion

Kurz gesagt: Sie können und sollten den Namespace verwenden, indem Sie Deklarationen und Anweisungen in Ihren Implementierungsdateien nach # include-Anweisungen großzügig 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 nutzbar .

128 robson3.14 Sep 21 2009 at 22:47

Man sollte die usingDirektive nicht im globalen Bereich verwenden, insbesondere in Headern. Es gibt jedoch Situationen, in denen dies auch in einer Header-Datei 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 sie kürzer ist und mit benutzerdefinierten Gleitkommatypen (über argumentabhängige Suche (ADL)) arbeiten kann.

100 towi Jan 18 2013 at 16:34

Verwenden Sie es nicht global

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

  • Sie überladen 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 andere Leser Ihres Quellcodes gilt, gilt umso mehr für den häufigsten Leser: Sie selbst. Komm in ein oder zwei Jahren zurück und schau mal ...
  • Wenn Sie nur darüber sprechen, sind using namespace stdSie sich möglicherweise nicht all der Dinge bewusst, die Sie greifen - und wenn Sie eine weitere hinzufügen #includeoder zu einer neuen C ++ - Version wechseln, können Namenskonflikte auftreten, die Ihnen nicht bekannt waren.

Sie können es lokal verwenden

Gehen Sie voran und verwenden Sie es lokal (fast) frei. Dies verhindert natürlich, dass Sie sich wiederholen std::- und Wiederholung ist auch schlecht.

Eine Redewendung für die lokale Verwendung

In C ++ 03 gab es eine Redewendung - Boilerplate-Code - zum Implementieren einer swapFunktion für Ihre Klassen. Es wurde vorgeschlagen, dass Sie tatsächlich ein lokales 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 macht die folgende Magie:

  • Der Compiler wählt das std::swapfür value_, dh void std::swap(int, int).
  • Wenn Sie eine Überladung void swap(Child&, Child&)implementiert haben, wählt der Compiler diese aus.
  • Wenn Sie diese Überlastung nicht haben, verwendet der Compiler diese void std::swap(Child&,Child&)und versucht, sie am besten auszutauschen.

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

81 sth Sep 21 2009 at 10:23

Wenn Sie die richtigen Header - Dateien importieren Sie plötzlich Namen wie hex, left, plusoder countin Ihrem globalen Rahmen. Dies kann überraschend sein, wenn Sie nicht wissen, dass std::diese Namen enthalten sind. Wenn Sie auch versuchen, diese Namen lokal zu verwenden, kann dies zu Verwirrung führen.

Wenn sich alle Standardmaterialien in einem eigenen Namespace befinden, müssen Sie sich keine Gedanken über Namenskollisionen mit Ihrem Code oder anderen Bibliotheken machen.

52 MartinBeckett Sep 21 2009 at 10:13

Ein weiterer Grund ist die Überraschung.

Wenn ich sehe cout << blah, anstatt zu std::cout << blahdenken: Was ist das cout? Ist es die normale cout? Ist es etwas Besonderes?

49 AlexanderPoluektov Mar 29 2011 at 15:10

Erfahrene Programmierer verwenden alles, was ihre Probleme löst, und vermeiden alles, was neue Probleme verursacht. Aus genau diesem Grund vermeiden sie Verwendungsanweisungen 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 diese guten Gründe ? Manchmal möchten Programmierer ADL explizit deaktivieren, manchmal möchten sie eindeutig unterscheiden.

Folgendes ist also in Ordnung:

  1. Using-Direktiven und using-Deklarationen auf Funktionsebene in den Implementierungen von Funktionen
  2. Verwendungsdeklarationen auf Quelldateiebene in Quelldateien
  3. (Manchmal) Verwendungsanweisungen auf Quelldateiebene
46 Oleksiy Aug 29 2013 at 16:44

Ich bin damit einverstanden, dass es nicht global verwendet werden sollte, aber es ist nicht so böse, es lokal zu verwenden, wie in a namespace. Hier ist ein Beispiel aus "The C ++ Programming Language" :

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 deklariert wurden His_lib::String) haben Vorrang vor Namen, die durch eine using-Direktive ( using namespace Her_lib) in einem anderen Bereich zugänglich gemacht werden .

32 Yelonek Sep 21 2009 at 16:34

Ich halte es auch für eine schlechte Praxis. Warum? Nur eines Tages dachte ich, dass die Funktion eines Namespace darin besteht, Dinge zu teilen, also sollte ich es nicht verderben, 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, mit der sie sich verbreitet #include). Ich denke, dass niemand vernünftig jemals einen Stream coutoder nennen wird cin. ;)

27 gnasher729 Mar 14 2014 at 00:22

Es ist schön, Code zu sehen und zu wissen, was er tut. Wenn ich sehe, std::coutweiß ich, dass das der coutStream der stdBibliothek ist. Wenn ich sehe, coutweiß ich es nicht. Es könnte der coutStrom der stdBibliothek sein. Oder es könnten int cout = 0;zehn Zeilen höher in derselben Funktion sein. Oder eine staticVariable mit dem Namen coutin dieser Datei. Es könnte alles sein.

Nehmen Sie jetzt eine Millionen-Zeilen-Codebasis, die nicht besonders groß ist, und suchen Sie nach einem Fehler, was bedeutet, dass Sie wissen, dass diese eine Million Zeilen eine Zeile enthält, die nicht das tut, was sie tun soll. cout << 1;könnte einen static intNamen lesen cout, ihn um ein Bit nach links verschieben und das Ergebnis wegwerfen. Auf der Suche nach einem Fehler müsste ich das überprüfen. Kannst du sehen, wie ich es wirklich am liebsten sehe std::cout?

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 liebe 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.

25 PreetSangha Sep 21 2009 at 10:14

Es geht darum, Komplexität zu managen. Wenn Sie den Namespace verwenden, werden Dinge eingezogen, die Sie nicht möchten, und daher wird das Debuggen möglicherweise schwieriger (ich sage möglicherweise). Die Verwendung von std :: überall ist schwieriger zu lesen (mehr Text und all das).

Pferde für Kurse - verwalten Sie Ihre Komplexität so gut Sie können und fühlen Sie sich in der Lage.

20 RonWarholic Sep 21 2009 at 10:19

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 anderen Importen haben, müssen Sie eine Menge Abhängigkeiten durchlaufen, um das Problem herauszufinden. Das Schlimmste daran ist, dass Sie abhängig von den widersprüchlichen Definitionen in anderen Modulen nicht verwandte Fehler erhalten können.

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 begrenzten Bereichen zu tun, aber ich hatte nie ein Problem damit, die zusätzlichen fünf Zeichen einzugeben, um zu klären, woher meine Funktionen stammen.

19 Kevin Sep 03 2016 at 03:06

Ein konkretes Beispiel zur Klärung des Problems. Stellen Sie sich eine Situation, wo Sie zwei Bibliotheken haben, foound bar, jede mit ihrem eigenen Namensraum:

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

namespace bar {
    ...
}

Nehmen wir nun an, Sie verwenden foound barzusammen in Ihrem eigenen Programm wie folgt:

using namespace foo;
using namespace bar;

void main() {
    a(42);
}

An diesem Punkt ist alles in Ordnung. Wenn Sie Ihr Programm ausführen, wird "etwas tun" ausgeführt. Aber später aktualisieren Sie barund sagen wir, es hat sich geändert wie folgt:

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

An dieser Stelle 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 verdeutlichen, dass "a" bedeutet foo::a. Das ist unerwünscht, aber zum Glück ist es ziemlich einfach (fügen Sie einfach foo::vor allen Aufrufen hinzu, adass der Compiler dies als mehrdeutig markiert).

Stellen Sie sich jedoch ein alternatives Szenario vor, in dem sich die Leiste geändert hat, um stattdessen so auszusehen:

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

An diesem Punkt a(42)bindet sich Ihr Aufruf, sich plötzlich an etwas zu binden, bar::aanstatt foo::aetwas zu tun, und es tut etwas völlig anderes. Keine Compilerwarnung oder so. Ihr Programm beginnt nur stillschweigend, etwas völlig anderes als zuvor zu tun.

Wenn Sie einen Namespace verwenden, riskieren Sie ein solches Szenario, weshalb es für Benutzer unangenehm ist, Namespaces zu verwenden. Je mehr Dinge sich in einem Namespace befinden, desto größer ist das Risiko von Konflikten. Daher ist es für Benutzer möglicherweise noch unangenehmer, einen Namespace zu verwenden std(aufgrund der Anzahl der Dinge in diesem Namespace) 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 in beide Richtungen sehen. 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 ziemlich seltene Auswirkung auf Zuverlässigkeit / Wartbarkeit. Der "beste" Kompromiss bestimmt Ihr Projekt und Ihre Prioritäten.

18 user2645752 Nov 09 2013 at 22:09

Die gleichzeitige Verwendung vieler Namespaces ist natürlich ein Rezept für eine Katastrophe, aber die Verwendung von NUR Namespace stdund nur Namespace stdist 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 war's.

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 bei der Verwendung von Namespaces. Sie sollten nicht mehr als eine gleichzeitig verwenden. Es sei denn, es ist dein eigenes. Eine Neudefinition wird also nicht stattfinden.

18 DustinGetz Sep 21 2009 at 11:04
  1. Sie müssen in der Lage sein, Code zu lesen, der von Personen geschrieben wurde, die andere Meinungen zu Stil und Best Practices haben als Sie.

  2. Wenn Sie nur verwenden cout, wird niemand verwirrt. Wenn jedoch viele Namespaces herumfliegen und Sie diese Klasse sehen und nicht genau wissen, was sie bewirkt, fungiert der explizite Namespace als eine Art Kommentar. Sie können auf den ersten Blick sehen, "oh, das ist eine Dateisystemoperation" oder "das macht Netzwerkkram".

14 Carl Feb 12 2015 at 07:40

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

Normalerweise verwende ich es in meiner Klassendeklaration, da Methoden in einer Klasse in der Regel mit ähnlichen Datentypen (den Mitgliedern) umgehen und ein typedef die Möglichkeit bietet, einen Namen zuzuweisen, der im Kontext der Klasse von Bedeutung ist. Dies unterstützt tatsächlich die Lesbarkeit in den Definitionen der Klassenmethoden.

// 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;
}
14 RohanSingh Apr 05 2015 at 19:56

Ein Namespace ist ein benannter Bereich. Namespaces werden verwendet, um verwandte Deklarationen zu gruppieren und separate Elemente getrennt zu halten. 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 Schriftsteller eine Ablenkung sein. Folglich 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 dazu, wie explizit auf einen nichtlokalen Namen verwiesen werden soll.

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

11 Nithin Dec 31 2014 at 15:00

Ein Beispiel, bei dem using namespace stdein Kompilierungsfehler aufgrund der Mehrdeutigkeit der Zählung ausgelöst wird, was auch eine Funktion in der Algorithmusbibliothek ist.

#include <iostream>
#include <algorithm>

using namespace std;

int count = 1;
int main() {
    cout << count << endl;
}
10 CryogenicNeo Apr 24 2018 at 00:15

Dies verschlechtert die Leistung Ihrer Software oder Ihres Projekts nicht. Die Aufnahme des Namespace am Anfang Ihres Quellcodes ist nicht schlecht. Die Aufnahme der using namespace stdAnweisung hängt von Ihren Anforderungen und der Art und Weise ab, wie Sie die Software oder das Projekt entwickeln.

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

Wie auf dieser Seite erwähnt :

Die Anweisung mit dem Namespace std wird im Allgemeinen als schlechte Praxis 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 stark nutzen und sicher wissen, dass nichts kollidieren wird.

Einige Leute hatten gesagt, dass es eine schlechte Praxis ist, die using namespace stdin Ihre Quelldateien aufzunehmen, da Sie von diesem Namespace aus alle Funktionen und Variablen aufrufen. Wenn Sie eine neue Funktion mit demselben Namen wie eine andere in der enthaltene Funktion definieren namespace stdmöchten, überladen Sie die Funktion und es können Probleme beim Kompilieren oder Ausführen auftreten. Es wird nicht wie erwartet kompiliert oder ausgeführt.

Wie auf dieser 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. Nehmen wir ein paar Beispiele, um zu verstehen, warum dies möglicherweise nicht so gut ist

...

Jetzt, 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 cout verweist? Der Compiler erkennt dies möglicherweise und kompiliert das Programm nicht. Im schlimmsten Fall kann das Programm zwar noch kompilieren, aber die falsche Funktion aufrufen, da wir nie angegeben haben, zu welchem ​​Namespace der Bezeichner gehört.

8 Dr.Watson Sep 21 2009 at 10:34

Ich denke nicht, dass es unter allen Umständen unbedingt eine schlechte Praxis ist, aber Sie müssen vorsichtig sein, wenn Sie es verwenden. Wenn Sie eine Bibliothek schreiben, sollten Sie wahrscheinlich die Bereichsauflösungsoperatoren mit dem Namespace verwenden, um zu verhindern, dass Ihre Bibliothek mit anderen Bibliotheken in Kontakt kommt. Für Code auf Anwendungsebene sehe ich nichts Falsches daran.

8 Noname Oct 14 2014 at 00:30

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

Wenn Sie einen Funktionsnamen suchen möchten, der möglicherweise ein ziemlich gebräuchlicher Name ist, ihn aber nur im stdNamespace finden möchten (oder umgekehrt - Sie möchten alle Aufrufe ändern, die sich nicht im Namespace std, Namespace Xusw. befinden), Wie schlagen Sie das 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 "das ist nicht mein Code ... ich verwende die Standardbibliothek" oder ob es etwas anderes ist, aber ich denke, es sieht besser aus. Dies könnte seltsam sein, da ich erst kürzlich in C ++ eingestiegen bin (C und andere Sprachen werden viel länger verwendet und immer noch verwendet und C ist meine Lieblingssprache aller Zeiten, direkt über der Assembly).

Es gibt noch eine andere Sache, obwohl sie etwas mit dem oben Gesagten zu tun hat und worauf andere hinweisen. Obwohl dies eine schlechte Praxis sein kann, reserviere ich manchmal std::namedie Standardbibliotheksversion und den Namen für die programmspezifische Implementierung. Ja, in der Tat könnte dies Sie beißen und Sie hart beißen, aber es kommt darauf an, dass ich dieses Projekt von Grund auf neu gestartet habe und ich der einzige Programmierer dafür bin. Beispiel: Ich überlade std::stringund nenne es string. Ich habe hilfreiche Ergänzungen. Ich habe es teilweise aufgrund meiner Tendenz zu Kleinbuchstaben unter C und Unix (+ Linux) gemacht.

Außerdem können Sie Namespace-Aliase haben. Hier ist ein Beispiel dafür, wo es nützlich ist, auf das möglicherweise nicht Bezug genommen wurde. Ich benutze den C ++ 11 Standard und speziell mit libstdc ++. Nun, es hat keine vollständige std::regexUnterstützung. Sicher, es wird kompiliert, aber es löst eine Ausnahme aus, da es sich um einen Fehler des Programmierers handelt. Aber es ist mangelnde Umsetzung.

So habe ich es gelöst. Installieren Sie den regulären Ausdruck von Boost und verknüpfen Sie ihn. Anschließend gehe ich folgendermaßen vor: Wenn libstdc ++ ihn vollständig implementiert hat, muss ich nur diesen Block entfernen und der Code bleibt gleich:

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 es für mein Projekt sauber hält und es gleichzeitig spezifisch macht: Richtig, ich muss Boost verwenden, aber ich verwende es so, wie es libstdc ++ irgendwann haben wird. Ja, das Starten eines eigenen Projekts und das Beginnen mit einem Standard (...) am Anfang trägt wesentlich dazu bei, Wartung, Entwicklung und alles, was mit dem Projekt zu tun hat, zu unterstützen!

Nur um etwas zu verdeutlichen: Ich halte es eigentlich nicht für eine gute Idee, einen Namen einer Klasse / was auch immer in der STL absichtlich und genauer anstelle von zu verwenden. Die Zeichenfolge ist für mich die Ausnahme (ignorieren Sie das erste, obige oder zweite Wortspiel, wenn Sie müssen) für mich, da mir die Idee von 'Zeichenfolge' nicht gefallen hat.

So wie es ist, bin ich immer noch sehr voreingenommen gegenüber C und voreingenommen gegenüber C ++. Sparsame Details, vieles, woran ich arbeite, passt mehr zu C (aber es war eine gute Übung und eine gute Möglichkeit, mich dazu zu bringen, a. Eine andere Sprache zu lernen und b. Nicht weniger voreingenommen gegenüber Objekten / Klassen / usw. zu sein, was vielleicht besser gesagt wird als weniger verschlossen, weniger arrogant und mehr akzeptierend.). Aber was nützlich ist , ist das, was einige bereits vorgeschlagen haben: Ich verwende tatsächlich list (es ist ziemlich allgemein, nicht wahr?) Und sortiere (dasselbe), um zwei zu benennen, die einen Namenskonflikt verursachen würden, wenn ich das tun würde using namespace std;, und so weiter Zu diesem Zweck ziehe ich es vor, spezifisch zu sein, die Kontrolle zu behalten und zu wissen, dass ich es spezifizieren muss, wenn ich beabsichtige, dass es die Standardverwendung ist. Einfach gesagt: keine Annahme erlaubt.

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

8 EngineDev Aug 21 2016 at 05:55

Nach meinen Erfahrungen können Sie, wenn Sie mehrere Bibliotheken haben, die beispielsweise verwenden cout, aber für einen anderen Zweck die falsche verwenden cout.

Wenn ich zum Beispiel using namespace std;und using namespace otherlib;und nur cout(was zufällig in beiden ist) anstelle von std::cout(oder 'otherlib::cout') eingebe, verwenden Sie möglicherweise die falsche und erhalten Fehler. Es ist viel effektiver und effizienter zu bedienen std::cout.

8 SwissFrank May 23 2019 at 05:05

Es ist von Fall zu Fall. Wir möchten die "Gesamtbetriebskosten" der Software über ihre Lebensdauer minimieren. „Using namespace std“ besagt , hat einige Kosten, aber nicht mit ihm auch eine Kosten in Lesbarkeit hat.

Die Leute weisen zu Recht darauf hin, dass bei Verwendung der Standardbibliothek, wenn die Standardbibliothek neue Symbole und Definitionen einführt, der Code nicht mehr kompiliert wird und Sie möglicherweise gezwungen sind, Variablen umzubenennen. Und dennoch ist dies auf lange Sicht wahrscheinlich gut, da zukünftige Betreuer vorübergehend verwirrt oder abgelenkt sein werden, wenn Sie ein Schlüsselwort für einen überraschenden Zweck verwenden.

Sie möchten beispielsweise keine Vorlage namens Vektor haben, die nicht allen anderen bekannt ist. Und die Anzahl der neuen Definitionen, die auf diese Weise in die C ++ - Bibliothek eingeführt wurden, ist klein genug, dass sie möglicherweise einfach nicht auftauchen. Es ist ein Kosten mit dieser Art von Veränderung zu tun, aber die Kosten sind nicht hoch und wird durch die Klarheit gewonnen , indem nicht mit Offset - stdSymbolnamen für andere Zwecke.

Angesichts der Anzahl der Klassen, Variablen und Funktionen kann die Angabe std::aller Klassen Ihren Code um 50% aufblähen und es schwieriger machen, sich zurechtzufinden. Ein Algorithmus oder Schritt in einer Methode, der auf einem Bildschirm voller Code ausgeführt werden kann, erfordert nun das Scrollen hin und her, um zu folgen. Dies ist ein echter Kostenfaktor. Es mag wohl keine hohen Kosten sein, aber Leute, die leugnen, dass es überhaupt existiert, sind unerfahren, dogmatisch oder einfach falsch.

Ich würde die folgenden Regeln anbieten:

  1. stdunterscheidet sich von allen anderen Bibliotheken. Es ist die einzige Bibliothek, die jeder grundsätzlich kennen muss, und meiner Ansicht nach wird sie am besten als Teil der Sprache betrachtet. Im Allgemeinen gibt es einen hervorragenden Fall, using namespace stdauch wenn es keine für andere Bibliotheken gibt.

  2. Erzwingen Sie niemals die Entscheidung dem Autor einer Kompilierungseinheit (einer CPP-Datei), indem Sie diese usingin einen Header einfügen . Immer verschieben die Entscheidung der Übersetzungseinheit Autor. Selbst in einem Projekt, das sich für die Verwendung using namespace stdüberall entschieden hat, können einige Module in Ordnung sein, die am besten als Ausnahmen von dieser Regel behandelt werden.

  3. Obwohl Sie mit der Namespace-Funktion viele Module mit gleich definierten Symbolen verwenden 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 auf lange Sicht wahrscheinlich besser, Ihre Klasse umzubenennen , wenn Sie eine Klasse mit dem Namen haben foound eine Klasse mit dem Namen stdeinführen foo.

  4. Eine Alternative zur Verwendung von Namespaces besteht darin, Namespace-Symbole manuell durch Präfixe zu versehen. Ich habe zwei Bibliotheken, die ich seit Jahrzehnten benutze. Beide beginnen als C-Bibliotheken, wobei jedem Symbol "AK" oder "SCWin" vorangestellt ist. Im Allgemeinen ist dies so, als würde man das Konstrukt "using" vermeiden, aber man schreibt keine Doppelpunkte. AK::foo()ist stattdessen AKFoo(). Dadurch wird der Code um 5-10% dichter und weniger ausführlich. Der einzige Nachteil besteht darin, dass Sie große Probleme haben, wenn Sie zwei solcher Bibliotheken mit demselben Präfix verwenden müssen. Beachten Sie, dass die X Window-Bibliotheken in dieser Hinsicht hervorragend sind, außer dass sie vergessen haben, dies mit ein paar #defines zu tun: TRUE und FALSE sollten XTRUE und XFALSE gewesen sein, und dies führte zu einem Namespace-Konflikt mit Sybase oder Oracle, die ebenfalls TRUE und FALSE verwendeten mit unterschiedlichen Werten! (ASCII 0 und 1 im Fall der Datenbank!) Ein besonderer Vorteil davon ist, dass es scheinbar ohne Präprozessordefinitionen gilt, während das C ++ using/ namespaceSystem sie nicht verarbeitet. Ein schöner Vorteil davon ist, dass es eine organische Neigung von einem Teil eines Projekts zu einer Bibliothek gibt. In einer großen Anwendung von mir werden alle Fensterklassen vorangestellt Win, alle Signalverarbeitungsmodule Mod und so weiter. Es besteht nur eine geringe Wahrscheinlichkeit, dass eines dieser Elemente wiederverwendet wird, sodass es keinen praktischen Vorteil hat, jede Gruppe zu einer Bibliothek zu machen, aber es wird in wenigen Sekunden deutlich, wie das Projekt in Teilprojekte zerfällt.

7 AugustKarlstrom Apr 11 2013 at 21:22

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.

7 MathGladiator Sep 21 2009 at 10:15

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

7 adn.911 Nov 30 2017 at 23:24

Dies ist eine schlechte Praxis, die oft als globale Verschmutzung durch Namespaces bezeichnet wird. Probleme können auftreten, wenn mehr als ein Namespace denselben Funktionsnamen mit Signatur hat. Dann muss der Compiler nicht eindeutig entscheiden, welchen er aufrufen möchte std::cout. Dies alles kann vermieden werden, wenn Sie den Namespace mit Ihrem Funktionsaufruf wie angeben . Hoffe das hilft. :) :)

6 NoneyoGetit Jun 28 2013 at 03:33

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 wie im Namespace std beeinflussen oder verwenden. Das ist sehr selbstverständlich, 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 ... zu sagen "Verlasse dich nicht darauf, dass dies vorhanden ist" bedeutet nur, dass du dich darauf verlässt, dass es NICHT vorhanden ist. Sie werden ständig Probleme haben, Codefragmente auszuleihen und ständig zu reparieren. Halten Sie einfach Ihre benutzerdefinierten und ausgeliehenen Inhalte in einem begrenzten Umfang, wie sie sein sollten, und gehen Sie SEHR sparsam mit Globals um (ehrlich gesagt sollten Globals fast immer das letzte Mittel sein, um "jetzt kompilieren, später vernünftig"). Wirklich, ich denke, es ist ein schlechter Rat von Ihrem Lehrer, weil die Verwendung von std sowohl für "cout" als auch für "std :: cout" funktioniert, aber NICHT für "std :: cout". Sie werden nicht immer das Glück haben, Ihren gesamten Code zu schreiben.

HINWEIS: Konzentrieren Sie sich nicht zu sehr auf Effizienzprobleme, bis Sie tatsächlich ein wenig über die Funktionsweise von Compilern gelernt haben. 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.