C++-Standardbibliothek: Wie schreibt man Wrapper für cout, cerr, cin und endl?

Lesezeit: 7 Minuten

Benutzer-Avatar
Ashwin Nanjappa

mag ich nicht using namespace stdaber ich bin es auch leid, tippen zu müssen std:: vor jedem cout, cin, cerr und endl. Also dachte ich daran, ihnen kürzere neue Namen wie diesen zu geben:

// STLWrapper.h

#include <iostream>
#include <string>

extern std::ostream& Cout;
extern std::ostream& Cerr;
extern std::istream& Cin;
extern std::string&  Endl;

// STLWrapper.cpp

#include "STLWrapper.h"

std::ostream& Cout = std::cout;
std::ostream& Cerr = std::cerr;
std::istream& Cerr = std::cin;
std::string _EndlStr("\n");
std::string& Endl = _EndlStr;

Das funktioniert. Aber gibt es irgendwelche Probleme in den oben genannten Punkten, die ich übersehe? Gibt es einen besseren Weg, dasselbe zu erreichen?

  • Dies ist nur in Ordnung, wenn Sie ein Ein-Mann-Unternehmen sind und niemand sonst den Code jemals lesen wird. Verknüpfungen wie diese dienen nur dazu, den Code zu verschleiern, und sind selten eine gute Idee für ein Entwicklerteam.

    – Martin York

    21. Mai 2010 um 10:27 Uhr

  • Martin: Punkt notiert. Ja, dies ist möglicherweise keine gute Idee, wenn Code mit anderen Personen verwendet wird.

    – Ashwin Nanjappa

    21. Mai 2010 um 10:29 Uhr

  • Das std::string& Endl hier definiert hat eine andere Funktionalität als std::endl die versucht, den Puffer zu leeren.

    – Noch ein Parker

    1. April 2015 um 16:38 Uhr


Benutzer-Avatar
sbi

Alex hat Ihnen eine Antwort gegeben, wie Sie dieses Problem syntaktisch lösen können. Ich möchte jedoch auf zwei weitere Argumente zu diesem Thema hinweisen:

  1. Egal, ob Sie eine beschäftigen Direktive verwenden (using namespace std) oder seine kleinere böse Schwester, a Deklaration verwenden (using std::cout), kann eine Überlastung zu bösen Überraschungen führen. Es ist nicht viel Aufwand zu tippen std:: verglichen mit eine halbe Nacht mit dem Debuggen verbringen um Ihren Code herauszufinden aufgerufen std::distance() statt deiner eigenen distance() funktionieren, nur weil du einen kleinen Fehler gemacht hast und std::distance() zufällig ist eine bessere Übereinstimmung.

  2. Eine Codezeile wird einmal geschriebenaber – je nach Lebensdauer – es wird zehn-, hundert- und manche sogar tausendmal gelesen. So die Zeit, die zum Schreiben einer Codezeile benötigt wird, spielt einfach keine Rolle, wichtig ist nur die Zeit, die zum Lesen und Interpretieren einer Codezeile benötigt wird. Auch wenn es dreimal so lange dauert, eine Zeile mit allem Richtigen zu schreiben std:: an Ort und Stelle, wenn es das Lesen nur 10% schneller macht, ist es immer noch die Mühe wert.
    Die wichtige Frage ist also: Ist es einfacher, eine Codezeile mit all dem zu lesen und zu interpretieren? std:: an Ort und Stelle oder ist es schwieriger? Aus einer anderen Antwort:

    Hier noch ein Datenpunkt: Vor vielen, vielen Jahren fand ich es auch lästig, alles aus der Standardbibliothek mit voranstellen zu müssen std::. Dann habe ich in einem Projekt gearbeitet, wo am Anfang entschieden wurde, dass beides using Direktiven und Deklarationen sind mit Ausnahme von Funktionsbereichen verboten. Erraten Sie, was? Die meisten von uns brauchten nur wenige Wochen, um sich daran zu gewöhnen, das Präfix zu schreiben, und nach ein paar weiteren Wochen waren sich die meisten sogar einig, dass es tatsächlich den Code erstellte besser lesbar. (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.)

    Innerhalb eines Jahrzehnts wuchs dieses Projekt auf mehrere Millionen Codezeilen an. Da diese Diskussionen immer wieder auftauchen, war ich mal gespannt wie oft der (erlaubte) Funktionsumfang ist using tatsächlich in dem Projekt verwendet wurde. Ich habe die Quellen dafür durchsucht und nur ein oder zwei Dutzend Stellen gefunden, an denen es verwendet wurde. Das deutet für mich darauf hin, einmal versucht, Entwickler nicht gefunden std:: schmerzhaft genug Verwenden von Direktiven sogar einmal alle 100kLoC auch dort, wo es erlaubt war.

    Ich finde es traurig, dass jedes Buch und Tutorial überspringt std::, weil sich die Leute daran gewöhnen, den Code so zu lesen. Als ich mehrere Jahre lang C++ unterrichtete (nach der oben genannten Erfahrung), sagte ich meinen Schülern, dass ich keine sehen möchte using Direktive oder Deklaration in ihrem Code. (Die einzige Ausnahme von dieser Regel ist using std::swapBTW, die Sie benötigen, um zu haben swap(a,b) Überladungen außerhalb des Namespace aufnehmen std.) Sobald sie sich daran gewöhnt hatten, machte es ihnen nichts aus und als sie danach gefragt wurden, sagten sie, sie hätten Code ohne das gefunden std:: Präfix verwirrend. Einige fügten sogar hinzu std:: Präfix für Code, den sie aus einem Buch oder Tutorial eingegeben haben, das es nicht hatte.

Fazit: Was ist so schwer am Tippen std:: dass sich alle so darüber aufregen? Mittlerweile mache ich das seit >15 Jahren und vermisse es nicht using überhaupt.

  • Sbi: Ich muss zugeben, dass ich schon früh von Code aus Büchern oder anderen Quellen beeinflusst wurde, die „using“ verwenden. Ich könnte ein bisschen von ähnlichen Anweisungen in Java & Python beeinflusst worden sein. Nachdem ich über Ihre Argumentation nachgedacht habe (und keine bessere Alternative gesehen habe), habe ich mich entschieden, den Code so zu korrigieren, dass überall std:: verwendet wird. Danke, dass du dir die Zeit für eine ausführliche Antwort genommen hast 🙂

    – Ashwin Nanjappa

    21. Mai 2010 um 10:39 Uhr


  • +1 (ich wünschte, ich könnte mehr tun) für “Eine Codezeile wird einmal geschrieben, aber – abhängig von ihrer Lebensdauer, wird sie zehn-, hundert- und manche sogar tausendmal gelesen. Also die Zeit, die zum Schreiben einer Zeile benötigt wird Code spielt einfach überhaupt keine Rolle, wichtig ist nur die Zeit, die zum Lesen einer Zeile und zum Interpretieren des Codes benötigt wird. — So wahr, aber so schwierig, dies den Kollegen zu überzeugen.

    – Arun

    24. Mai 2010 um 7:44 Uhr

  • Hm, nicht gesehen. Ich bin auch davon überzeugt, dass Präfixe für mehr Klarheit sorgen, insbesondere wenn Namensräume und Unterordner übereinstimmen, sodass Sie wissen, welches Include dieses bestimmte Objekt gebracht hat 🙂

    – Matthias M.

    27. August 2010 um 16:42 Uhr

  • @Wir können nichts tun: auto ist nicht da, um die Eingabe zu reduzieren, sondern um Variablen von Typen zu erstellen, für die Sie den Namen nicht buchstabieren können. Es kommt einfach vor, dass Sie es verwenden können, um das Tippen zu reduzieren, aber die Hauptfunktion, die es hinzufügt, besteht darin, Folgendes schreiben zu können: auto lambda = [](int x){ return x*x; };ohne die es nicht geht auto.

    – David Rodríguez – Dribeas

    9. Februar 2011 um 17:28 Uhr

  • @There: Sie haben vielleicht bemerkt, dass Ihre letzten beiden Kommentare zu David verschwunden sind, nachdem ich sie als anstößig gekennzeichnet habe. Das ist nicht das erste Mal, dass ich das bei dir sehe. Und das ist der Moment, in dem ich diese Diskussion mit Ihnen beenden werde. Ich habe gelernt, Davids Einsichten zu respektieren und diskutiere gerne mit ihm, weil ich dabei viel lerne. Sie, OTOH, diskutieren nicht, um neue Erkenntnisse zu gewinnen, Sie diskutieren nur, um Ihren Standpunkt zu beweisen, und werden sich daher ärgern, wenn die Diskussion nicht Ihren Weg geht. Ich kann das sehr gut machen, ohne meine Zeit damit zu verschwenden. Einen schönen Tag noch.

    – sbi

    9. Februar 2011 um 21:17 Uhr

Warum nicht

using std::cin;
using std::cout;

und so weiter? Dann können Sie in Ihrem Code verwenden cin, coutund so weiter, ohne versehentlich den ganzen Rest zu injizieren std Namespace in Ihren Code.

  • [hand to head] Mir war nicht einmal bewusst, dass “using” mit Nicht-Namespace-Entitäten verwendet werden kann! Vielen Dank! 🙂

    – Ashwin Nanjappa

    21. Mai 2010 um 4:42 Uhr


  • @ashwin: using namespace_name::identifier wird als “Namespace-Deklaration” bezeichnet, wohingegen using namespace_name wird als “Namespace-Direktive” bezeichnet.

    – sbi

    21. Mai 2010 um 6:30 Uhr

  • Sbi: Vielen Dank dafür! Ich gehe jetzt zurück zu den Büchern, um alles über “Verwenden” zu lesen.

    – Ashwin Nanjappa

    21. Mai 2010 um 10:31 Uhr

  • @Ashwin: Sobald du nachgelesen hast using, kann es auch verwendet werden, um einen Basisklassenbezeichner in den Gültigkeitsbereich einer abgeleiteten Klasse zu bringen, sodass er für die Überladungsauflösung berücksichtigt wird, oder um den Bezeichner einer privaten Basis in der Schnittstelle einer abgeleiteten Klasse zugänglich zu machen. In freier Wildbahn habe ich die allerdings noch nicht gesehen.

    – sbi

    23. Mai 2010 um 22:06 Uhr

1013510cookie-checkC++-Standardbibliothek: Wie schreibt man Wrapper für cout, cerr, cin und endl?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy