Tipps zu meinem C++ code



  • MiMi85 schrieb:

    krümelkacker schrieb:

    Ein unnötiger globaler Zustand (textFiles) ist unschön.

    Wie löst man sowas dann am besten? An jede Methode die map mitzugeben, ist doch auch nicht schön oder?

    Doch, das ist schon besser. Noch besser sind kleinere Funktionen, die nicht 100 Parameter bekommen. ZB:

    long count_word_frequency(vector<string> const& words, string const& word);
    

    MiMi85 schrieb:

    krümelkacker schrieb:

    Du hast ein paar unnötige Kopien [...].

    Hm, vermutlich aus meinen Java-Kentnissen, einfach alles in ne extra Variable zu speichern, so wie es dort steht ^^ (string curTextFile = i->first;)
    Also Referenz auf ne const ->

    const string &curTextFile = i->first;
    

    Mit der Referenz wird dann keine Kopie erstellt, weil es nur auf das Objekt zeigt, richtig?

    Wenn Du schon so fragen musst, ist doch eigentlich klar, dass Du noch nicht wirklich fit in C++ bist. Also: Erstmal die Sprache richtig lernen. Dann das Buch "Effective C++" (3rd edition) lesen.

    Aber warum const, weil es sich nicht verändern soll?

    Ja, warum nicht? "Const correctness" ist was feines.

    Habe Informatik studiert, hatten aber wie gesagt, hautpsächlich Java.

    Ging mir auch so. Fand ich im Nachhinein sehr schade. Ich habe mir nach dem Studium C++ selbst beigebracht. Du kannst Die Praktikumsstelle ja annehnen, und dabei C++ lernen. Vielleicht wird das danach doch was mit der Anstellung. Ich würde mir dann aber an Deiner Stelle wirklich 2-3 C++ Bücher besorgen.

    kk



  • Naja eine Praktiktumsstelle war leider nicht verfügbar. Es kam halt nur der Kommentar, dass es so wie es jetzt ist, maximal für eine Praktikumsstelle reichen würde.

    Ich hab mich schon öfters umgesehen, nach Tutorials die spezielle für Java-Programmierer sind, zur Umstellung auf C++. Aber selbst dort wird nicht beschrieben, wann zb Pointer gentutz werden (sollten). Oder wann header files. Finde ich sehr schade.
    Schaut man sich sonst nach C++ Tutorials um, fangen diese meist ganz am Anfang an, mit "was sind variablen" etc. Das demotivert doch sehr schnell, weil man sich leicht verkaggert vorkommt ^^



  • Wie gesagt, ich war in der gleichen Lage. Vergiss Tutorials. Ich hatte TC++PL und EffC++ relativ fix durchgelesen. Es gingen dabei viele Lichter auf, fielen viele Groschen, etc. IMHO ideal für Umsteiger. Wenn's Dir also darum geht, viel komprimierte gute Information in kurzer Zeit aufzunehmen, bist Du mit den zwei Büchern gut beraten. Alles andere kommt dann mit der Zeit.

    kk



  • seldon schrieb:

    @eeeeeeeke:

    Ich bin der Ansicht, dass ein "Abstraction Freak" sich mindestens noch eine Akkumulatorvorlage für die Abfrage geschrieben hätte, der die Zwischenergebnisse in einen eigens für die Formatierung bestimmten Datentyp (d.h. mit entsprechendem operator<< versehenen) verpackt und in einen ostream_iterator geschmissen hätte.

    Aber mal in Ernst, wo ist da die große Abstraktion? Eine std::map mit einem eigenen Vergleichsfunktor zu versehen, ist nun wirklich kein besonders komplexer Anwendungsfall, und ansonsten habe ich da gerade mal eine Funktion und eine Funktionsvorlage. Viel einfacher wird das ganze eigentlich nicht mehr.

    Naja, wenn man für so eine Aufgabe bind und function auspackt, sieht mir das schon nach etwas zuviel abstrahiert aus. Und dieser std::locale sieht auch stark danach aus, das ganze irgendwie international zu halten, aber std::string verhindert das wieder.



  • eeeeeeeke schrieb:

    Naja, wenn man für so eine Aufgabe bind und function auspackt, sieht mir das schon nach etwas zuviel abstrahiert aus.

    Aber der Rest des Codes mit den maps sieht doch sehr kompakt und funktional aus. Finde ich gut so.

    Der große struct am Anfang, nur zum Stringvergleich, sieht schon etwas heftig aus. Den würde ich mindestens auf die Hälfte eindampfen

    struct string_compare_ci 
    {
    private:
      std::locale m_loc;
    public:
      string_compare_ci(std::locale const &loc = std::locale()) : m_loc(loc) { }
    
      bool operator()(const std::string &lhs,
                      const std::string &rhs) const 
      {
          return std::lexicographical_compare(lhs.begin(), lhs.end(),
                                              rhs.begin(), rhs.end(),
                                              [this] (char c1, char c2 ) 
                                              { return std::tolower(c1, m_loc) < std::tolower(c2, m_loc); } );
      }
    };
    

    wenn der Compiler sowas schon kann. (Oder sogar versuchen das ganze Ding durch Lambdas zu ersetzen, dann wäre es fast so elegant wie in C#.)



  • Das ist ein ziemlich merkwürdiges Verständnis von "Abstraktion" - ich benutze ja nur schon vorhandenen Kram. Natürlich hätte ich mir einen eigenen Funktor, der die Locale an die Funktion bindet, schreiben oder std::lexicographical_compare reimplementieren können, aber was hätte das gebracht, von Mehrarbeit abgesehen? Hätte ich string_compare_ci jetzt als Klassenvorlage aufgezogen, die einen Funktortyp zum Vergleichen der normalisierten Zeichen und eine Strategie zur Normalisierung der Zeichen erlaubt hätte, hätte ich die Kritik ja verstanden, aber so, wie's da steht, macht das Zeug schlicht das, was es muss.

    Die Locale ist übrigens für die korrekte Behandlung von Umlauten und anderen Sonderzeichen von Bedeutung. Wenn "nämlich" einmal am Satzanfang und einmal in der Satzmitte steht, bist du ohne ziemlich aufgeschmissen.

    @nn: Von der Verwendung von Lambda-Ausdrücken habe ich abgesehen, weil der neue Standard noch nicht verabschiedet und dementsprechend nicht von allen gängigen Compilern unterstützt wird. In Produktionscode hätte ich mich aber wohl bei Boost bedient, die haben etwas derartiges schon in der algorithms-Bibliothek.



  • seldon schrieb:

    aber so, wie's da steht, macht das Zeug schlicht das, was es muss.

    Ich stimme dir da zu. Gleichzeitig muss ich aber anerkennen, dass solcher Code geeignet ist unsichere Einsteiger in die Flucht zu schlagen.

    Aber das ist halt der, etwas kryptische, Charme von C++. Ich kann dem Threadersteller auch nur raten, die genannten Bücher durchzuarbeiten. Dann wird ihm vieles klarer werden.

    Und was die Lambdas, functional und bind angeht, vieleicht auch ein Buchtipp. Ich lese gerade "Real world functional programming", ist eigentlich ein Buch über C# und F#, aber danach sieht man manche der neuen Sachen in C++ auch aus einer ganz anderen Perspektive.



  • nn schrieb:

    Ich stimme dir da zu. Gleichzeitig muss ich aber anerkennen, dass solcher Code geeignet ist unsichere Einsteiger in die Flucht zu schlagen.

    Da mag was dran sein, aber es hat auch etwas Gefährliches, Anfängern nur Anfänger-C++ zu zeigen. Es ist, und ich bitte, in den Vergleich jetzt nicht zu viel reinzudeuten, ein bisschen wie mit Kindern und Babysprache - sie lernen mehr, wenn man normal zu ihnen spricht.

    Es mag durchaus sein, dass ein Anfänger das bind-Konstrukt nicht auf Anhieb durchschaut, aber auf Nachfrage erkläre ich gerne, was das alles bedeutet. Ein Anfänger wird (und muss) nicht alles wissen, aber ich halte es für respektlos, gleich davon auszugehen, dass er es nicht verstehen wird. Ein genaues Verständnis der dahinterliegenden Mechanismen braucht womöglich etwas Erfahrung und weitergehende Kenntnisse, aber mal ganz ehrlich, bevor jemand bis zum Kapitel "Operatorüberladung" gekommen ist, kann er den Mechanismus hinter

    std::cout << "Hallo, Welt!" << std::endl;
    

    auch nicht genau verstehen, und die Anwendung von std::tr1::bind und std::tr1::function ist so schwierig eigentlich nicht. Außerdem eröffnen diese Konstrukte einen ganz neuen Blickwinkel auf die Sprache, und es kann nicht schaden, angehende Programmierer damit früh in Berührung zu bringen.

    Naja, das ist jedenfalls meine Rechtfertigung. Man kann da wohl geteilter Meinung sein.



  • seldon schrieb:

    Da mag was dran sein, aber es hat auch etwas Gefährliches, Anfängern nur Anfänger-C++ zu zeigen. Es ist, und ich bitte, in den Vergleich jetzt nicht zu viel reinzudeuten, ein bisschen wie mit Kindern und Babysprache - sie lernen mehr, wenn man normal zu ihnen spricht.

    Ja das ist auch richtig. Auch sind Programmierer, die von einer anderen Sprache kommen, sicher auch keine Babies.

    Aber wenn man sieht, dass der halbe Quelltext in diesem Beispiel eigentlich nur dazu dient etwas zu machen, das woanders z.B. so aussieht

    var word_map_ci = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
    

    dann bestätigt das doch gewisse Vorurteile über C++. Gut, eigentlich haben wir hier ein Problem des Bibliotheksdesigns, die STL ist mächtig, aber manchmal können kleine Aufgaben komplexen Code erfordern.



  • [quote="nn"]

    seldon schrieb:

    Aber wenn man sieht, dass der halbe Quelltext in diesem Beispiel eigentlich nur dazu dient etwas zu machen, das woanders z.B. so aussieht

    var word_map_ci = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
    

    dann bestätigt das doch gewisse Vorurteile über C++. Gut, eigentlich haben wir hier ein Problem des Bibliotheksdesigns, die STL ist mächtig, aber manchmal können kleine Aufgaben komplexen Code erfordern.

    Und das ist das Problem mit Leuten, die nicht genug von C++ verstehen und meinen sich dann drüber beschweren zu müssen. Wäre es anders, wüsstest du das es Quatsch es was du sagst. In C++ kann man das gleiche in einer Zeile machen.
    Ich sage nur:

    //StringComparer könne genau wie in C# irgendwo in einer Lib definiert sein
    std::map<string,string,StringComparer::CurrenCultureIgnoreCase> word_map_ci;
    

    Seldons Beispiel macht deutlich mehr.


Anmelden zum Antworten