C++ ohne STL?



  • Ben04 schrieb:

    Ein Foo anzulegen könnte kostspielig sein und nur um zu testen ob das nächste was der Stream enthält ein Foo ist eines anlegen zu müssen klingt verschwenderisch. Was sich auch als sehr nützlich erwiesen hat war ein was_at.

    ich hab allerbeste erfahrungen mit

    Foo::Foo(istream& in)
    :Base1(in),
    Base2(in),
    member1(in),
    member2(in)
    {
    }
    

    es ist einfach nur schweineschnell. und einfach. und mir ausreichend wartbar. und die factory liest einfach immer die klassenkenzeichnung vor dem objekt und ruft den entsprechenden new auf. die virtual void writeAt schreibt vor die nutzdaten die klassenkennzeichnung. da kann xml mal ganz schön nach hause gehen. um's dem menschen noch ein wenig netter in den files zu machen, hab ich noch nach der klassenkenzeichnung "{\n" und nach den nutzdaten "}\n\n" geschrieben. geschrieben wurde ascii und zahlen hex (für speed). menschen können zwar drin rumändern, aber perl-scrips machen das noch besser.

    Eigentlich finde ich folgendes recht einfach als Test:

    if(in.peek() == EOF)
    

    istream::eof ist affig, da gebe ich dir recht.

    äh. peek() liefert nen char, alles ander wäre unfug, oder? da passt EOF nicht rein.



  • volkard schrieb:

    Ben04 schrieb:

    Ein Foo anzulegen könnte kostspielig sein und nur um zu testen ob das nächste was der Stream enthält ein Foo ist eines anlegen zu müssen klingt verschwenderisch. Was sich auch als sehr nützlich erwiesen hat war ein was_at.

    ich hab allerbeste erfahrungen mit

    Foo::Foo(istream& in)
    :Base1(in),
    Base2(in),
    member1(in),
    member2(in)
    {
    }
    

    es ist einfach nur schweineschnell. und einfach. und mir ausreichend wartbar. und die factory liest einfach immer die klassenkenzeichnung vor dem objekt und ruft den entsprechenden new auf. die virtual void writeAt schreibt vor die nutzdaten die klassenkennzeichnung. da kann xml mal ganz schön nach hause gehen. um's dem menschen noch ein wenig netter in den files zu machen, hab ich noch nach der klassenkenzeichnung "{\n" und nach den nutzdaten "}\n\n" geschrieben. geschrieben wurde ascii und zahlen hex (für speed). menschen können zwar drin rumändern, aber perl-scrips machen das noch besser.

    Klar ist das schweine schnelaber nur bedingt vom Menschen lesbar. So wie ich es sehe kommt ein Container nicht umher die Zahl der Elemente als erstes abzuspeichern (oder irre ich da?). Der User sieht dann 3 {1 5 6} fügt mal schnell ein Element hinzu und du hast 3 {1 5 6 7} und das wäre ein Problem. XML ist ja nicht so sehr für Schnelligkeit ausgelegt, eher für leichte Veränderbarkeit vom Menschen mit Notpad. Meiner Meinung nach vergleichst du 2 verschiedene Paar Schuhe.

    volkard schrieb:

    Eigentlich finde ich folgendes recht einfach als Test:

    if(in.peek() == EOF)
    

    istream::eof ist affig, da gebe ich dir recht.

    äh. peek() liefert nen char, alles ander wäre unfug, oder? da passt EOF nicht rein.

    peek() liefert aus genau diesem Grund ein int zurück.
    http://www.cppreference.com/cppio/peek.html



  • Hallo,
    wie gefallen euch eigentlich die boost::iostreams?

    http://www.boost.org/libs/iostreams/doc/index.html

    Mein erster Eindruck ist durchaus positiv (Filtering-Streams z.B. fand ich schon immer sehr nützlich). Hab' mich aber noch nicht intensiv genug damit beschäftigt um die Streams wirklich beurteilen zu können.



  • Ben04 schrieb:

    So wie ich es sehe kommt ein Container nicht umher die Zahl der Elemente als erstes abzuspeichern (oder irre ich da?). Der User sieht dann 3 {1 5 6} fügt mal schnell ein Element hinzu und du hast 3 {1 5 6 7} und das wäre ein Problem.

    jup.
    deswegen hatte ich da gemogelt und {1 5 6 7} nur gemacht und es war noch ok, weil containers selten sind. schlimm sind natürlich strings ohne die längenangabe am anfang.
    ich dachte an zwei sorten streams, plainstreams und binarystreams, normalerweise werden binarystreams verwendet, aber der user kann jederzeit die welt auch auf nen plainstream speichern oder von da laden. naja, als zukonftsvision. war so aber auch schon ok und ich hab statt 10 min (konkurrenz) nur 20 sec gebraucht für 30M strukturierte daten. hab das projekt aber nicht fortgeführt.



  • elise schrieb:

    warum nicht?
    printf zum bleistift.
    und wozu braucht es die string klasse *g*

    Hm, string meide ich irgendwie und bastel immer spezialisierte Alternativen (die wahrscheinlich viel schlechter sind, aber egal 😉 ). Ich denke die Stream-Klassen braucht man, sonst modelliert man sich seine Container eben selbst 😉



  • HumeSikkins schrieb:

    Hallo,
    wie gefallen euch eigentlich die boost::iostreams?

    http://www.boost.org/libs/iostreams/doc/index.html

    Mein erster Eindruck ist durchaus positiv (Filtering-Streams z.B. fand ich schon immer sehr nützlich). Hab' mich aber noch nicht intensiv genug damit beschäftigt um die Streams wirklich beurteilen zu können.

    Sieht cool aus. So ein bzip2- oder Regex-Filter kann schon praktisch sein und es ist schön, solche feinen Dinge in einer zusammenhängenden Bibliothek vorzufinden. Aus boost ist ganz schön was geworden.



  • volkard schrieb:

    ich dachte an zwei sorten streams, plainstreams und binarystreams, normalerweise werden binarystreams verwendet, aber der user kann jederzeit die welt auch auf nen plainstream speichern oder von da laden. naja, als zukonftsvision. war so aber auch schon ok und ich hab statt 10 min (konkurrenz) nur 20 sec gebraucht für 30M strukturierte daten. hab das projekt aber nicht fortgeführt.

    Du hast aber dafür die Eigenschaft geopfert, dass die Daten ohne weiteres vom Menschen lesbar sind. Die Idee 2 austauschbare Streamsorten zu benutzen hatte ich auch schon hab sie aber verworfen da beispielsweise XML nict bloß anders formatiert ist, sondern auch noch Metadaten benötigt.

    <a>
      <b>8</b>
      <c>12</c>
    </a>
    

    Eigentlich nur mit Metadaten sinnvoll.

    <Geburtstag>
      <Tag>8</Tag>
      <Monat>12</Monat>
    </Geburtstag>
    

    Zum generiren von XML braucht es also mehr Informationen als für binäre Representationen. Dann gibt es noch ein weiters Problem dies wäre auch gültiges XML

    <Geburtstag>
      <Monat>12</Monat>
      <Tag>8</Tag>
    </Geburtstag>
    

    Dies würde aber Probleme bereiten da die binären Streams mit Hilfe der Reihenfolge die Daten deuten.

    Meiner Meinung nach kann man nur die Zeichenquelle und Ausgabe teilen.

    @HumeSikkins Ich finde, dass es die IOStreams um sehr nützliche Funktionen erweitert. Diese auch gut umsetzt aber leider die alten Probleme nicht löst.



  • Ben04 schrieb:

    Die Idee 2 austauschbare Streamsorten zu benutzen hatte ich auch schon hab sie aber verworfen da beispielsweise XML nict bloß anders formatiert ist, sondern auch noch Metadaten benötigt.

    <a>
      <b>8</b>
      <c>12</c>
    </a>
    

    Eigentlich nur mit Metadaten sinnvoll.

    <Geburtstag>
      <Tag>8</Tag>
      <Monat>12</Monat>
    </Geburtstag>
    

    äh. es kann doch ein (mit RVO natürlich) :tag(readAttrib(in,"Tag")) sein. im binary-mode zu nollkosten weg und im normalemode auch nd im xml-mode wird halt lästig gehanselt.



  • volkard schrieb:

    äh. es kann doch ein (mit RVO natürlich) :tag(readAttrib(in,"Tag")) sein. im binary-mode zu nollkosten weg und im normalemode auch nd im xml-mode wird halt lästig gehanselt.

    Das würde natürlich gehen aber wieviel Informationen braucht man? Diese Frage kann man beantworten wenn man sich auf einige Formate beschränkt. Man kann aber keine allgemein gültige Antwort finden wie sie für ein System das für Ausweitbarkeit ausgelegt ist gebraucht werden würde.

    Desweiteren bin ich mir sicher, dass es in sehr vielen Fällen der Programmirer von vorn herein weiß welches Format er braucht. Zum Beispiel macht es keinen Sinn 30MB mit XML auf 100MB aufzupumpen allerdings wäre es auch keine gute Idee eine Konfigurationsdatei im binär Format zu schreiben. Ich glaube, dass es sehr viel Überzeugungsarbeit braucht um den Programmirer dazu zu bewegen da etwas sinnvolles hinzu schreiben wenn er genau weiß, dass er es nicht brauchen wird. Die Idee ist natürlich gut wenn man wirklich eine Duallösung braucht.



  • Ich finde das eigentlich relativ klar. Wenn ich einigermaßen in Echtzeit Objekte über ein Socket wo hin schicken möchte, werde ich eine binäre Repräsentation nehmen. Von Menschen nicht lesbar, effizient und ein bisschen unportabel. Sachen wie eine Konfiguration sollten als XML geschrieben werden. Aus

    class Configuration {
    public:
        string getName();
        void setName(string);
        ...
    };
    

    Muss dann automatisch sowas wie

    <Configuration>
        <name>Hanswurst</name>
    </Configuration>
    

    werden.
    Wenn ich es mega-portabel und unabhängig brauche, muss ein Serializer her, der sich an ein offenes Format wie SOAP (XML mit wahnsinnig viel Zusatzinformationen erzeugt, die ich noch nicht verstanden habe) hält.
    Es gibt kein besser oder schlechter, man wird doch immer klare Anforderungen an die Objektserialisierung haben und am besten, man hat für alles entsprechende Filter-Streams.



  • warum gleich xml?

    <Configuration>
        <name>Hanswurst</name>
    </Configuration>
    

    naja, ich schreib und editiere leiber

    Configuration
    {
        name: "Hanswurst"
    }
    


  • warum gleich xml?

    <Configuration>
    <name>Hanswurst</name>
    </Configuration>
    

    naja, ich schreib und editiere leiber

    Configuration
    {
        name: "Hanswurst"
    }
    

    Mein Kollege Klaus schreibt und ediert gerne:

    configuration
    begin
      name := 'Hanswurst'
    end
    

    Wozu braucht man schon Standards, wenn doch jeder sein eigenes Süppchen kochen kann 🙄 .



  • Der Anfang meines Beitrag sollte natürlich Volkard zitieren. Habe die Tags vergessen. Sorry.



  • kopf_schuettler schrieb:

    Wozu braucht man schon Standards, wenn doch jeder sein eigenes Süppchen kochen kann 🙄 .

    wozu *immer* xml nehmen? mehr augenmaß bei der verwendung der werkzeuge erbitte ich. sachen dort einsetzen, wo sie sinnvoll sind, aber nur dort.



  • @Volkard

    Sehr schwache Begründung!

    Wo macht denn XML weniger Sinn als deine Syntax 😕? Wo sind die konkreten Vorteile deiner Schreibweise.

    Volkard schrieb:

    wozu *immer* xml nehmen? mehr augenmaß bei der verwendung der werkzeuge erbitte ich. sachen dort einsetzen, wo sie sinnvoll sind, aber nur dort.

    Benutzt du je nach Applikation eine andere Syntax für deine Datenhaltung. XML bietet dir einen Standard, damit du nicht immer grübeln brauchst, wie du deine Daten speicherst. Damit hast du es überall einheitlich.



  • xml ist für den rechner nicht super-schnell und für den menschen unanenehm. da halt ich mich doch nicht an nen standard, nur weil es ihn gibt! ich benutze ja auch keine ungarische notation, nur weil es sie gibt.



  • XML ist für den Menschen sehr angenehm. Es muss ja keiner den XML-Quelltext direkt bearbeiten. Und es ist bei XML sehr leicht, schnell ein Programm hinzuhacken, dass das Objekt wiederherstellt, vorausgesetzt, man hat zumindest mal nen XML-Parser fertig. Ich kann mit Sicherheit schneller ein Programm schreiben, was solche Objekte aus der Datei ausliest, als du, wenn du dein Format nimmst und keinen fertigen Parser hast.
    Dass es für den Rechner nicht schnell ist, ist klar. Deshalb sollte man halt beide (oder mehr) Arten der Serialisierung haben, damit man das nehmen kann, was die Belange am besten erfüllt. Ich sehe aber keinen Grund für ein Format wie von dir vorgeschlagen. Entweder gleich binär oder richtig wartbar und allgemein akzeptiert (IMHO).



  • so, ich muss mich ja mal wieder zu dem äußern,was gesagt wurde:

    wozu war noch mal open/close da? mir scheint das einfach ein relikt aus alten tagen, als man noch c-stylish programmieren wollte.

    ich habs erst letztens benutzt: ich hab den fall, viele handles auf dateien gleichzeitig zu haben. nun ist es natürlich schlecht, wenn alle handles-sogar wenig genutzte-offen bleiben. Und so hab ich dann einen mechanismus entwickelt, der automatisch die am wenigsten benutzten dateien schließt, und wieder öffnet, sobald sie gebraucht werden. Und der benutzt halt open/close.

    Ein weiteres Problem ist die Vermischung von Dateien und Strömenen. Wieso zum Teufel soll ein Strom seakbar sein? Nicht alle Ströme sind es, die meisten sogar nicht! Hier wird gegen ein grundlegendes Konzept der Vererbung verstoßen. Eine Basisklasse ist die Schnittmenge der abgeleitenen Klassen und nicht deren Union.

    vorwärtsseeken kannst du in jedem strom. und wenn die implementation von seak nur 2millionen mal get() aufruft ;). das rückwärtsseeken ist das problem.

    Desweiteren ist das Puffern Aufgabe der Stromquelle. Dies heißt stream_buf sollt nur ein virtuelle Methoden read und write enthalten. Wenn die Quelle gepuffert werden soll dann ist das die Aufgabe des Implementierers von write und read. Hier schießen die Iostreams über ihre Aufgabe hinaus.

    schau dir doch die streambuf objekte an, nur sie puffern. die istreams und ostreams puffern garnichts. Und wenn du es hasst,dass irgendetwas gepuffert wird, dann bleib ruhig und schreib folgende zeile:

    str.rdbuf()->pubsetbuf(NULL,0);
    

    das puffern ist immer optional.

    Dann was bringt die Verbindung von Ein - und Ausgabe? Was ist der Vorteil von foo(iostream&) gegenüber von foo(istream&, ostream&)? Ich sehe nur Nachteile.

    der größte vorteil ist:

    foo(iostream& str){
        str<<"eingabe:"
        int i;
        str>>i;
    }
    

    das funktioniert problemlos.

    folgendes nicht immer:

    foo(istream& in, ostream& out){
        out<<"eingabe:"
        int i;
        in>>i;
    }
    

    damit die funktion funktioniert müssen in und out aneinander gebunden sein. ansonsten muss du vor jeder eingabe flush() aufrufen.

    ansonsten spricht nichts dagegen:

    foo(istream& in, ostream& out){...}
    
    iostream str;
    foo(str,str);
    

    zu schreiben. mehr als 2 streams aneinanderketten und synchron halten tut iostream nämlich nicht.

    Desweiteren müßten die Eingabefunktionen auch eine Möglichkeit haben den Strom bei einem Formatsfehler in einem ordentlichen Zustand zu belassen. Man kann nicht immer mit einem Zeichen im voraus bestimmen ob eine Eingabe scheitert oder nicht. Darum muß man mehrere Zeichen einlesen. Wenn es nun aber scheitert? Was machen wir mit den eingelesenen Zeichen?

    wozu? wenn du die streams benutzt, wirst du wohl wissen, was du erwartest. Und selbst wenn du nicht weist, was du erwartest, weist du normalerweise, wie groß der block "unbekannter Daten" ist. Wenn die eingabe kaputt ist, bleiben dir nicht viele möglichkeiten. mit kaputten daten kannst du nicht arbeiten. Entweder, es werden die daten dann neu angefordert, oder ne exception hat zu fliegen(wenn ne datei kaputt ist, kann man damit nicht mehr anständig weiterarbeiten. im besten fall kann man versuchen, die datei mit defaultwerten umzuschreiben).

    Und im fall unbekannter daten wirst du wohl nicht drumrumkommen, zu puffern. für sowas gibt es dann ja immernoch die stringstreams.

    Benutzt keiner Exceptions bei I/O-Fehlern?

    doch, aber nicht bei EOF. ich werf immer dann, wenn der stream kaputt ist, oder aus einem stream im eof zustand versucht wird, zu lesen.

    und dann zum Format thema:

    <Configuration>
    <name>Hanswurst</name>
    </Configuration>
    
    Configuration
    {
        name: "Hanswurst"
    }
    
    configuration
    begin
      name := 'Hanswurst'
    end
    

    is doch wirklich jacke wie Hose, welches Format die daten haben. wenn der eine das eine Format besser findet, soll er die andren links liegen lassen. Wichtig ist meiner meinung nur, dass-egal welches Format die daten haben- die endverarbeitung gleich ablaufen kann.



  • otze schrieb:

    Benutzt keiner Exceptions bei I/O-Fehlern?

    doch, aber nicht bei EOF. ich werf immer dann, wenn der stream kaputt ist, oder aus einem stream im eof zustand versucht wird, zu lesen.

    Glaube ich dir nicht, kann man so nämlich gar nicht einstellen. Du kannst einen Stream im nicht-EOF-Zustand haben und beim Lesen eine Exception kriegen mit der Begründung, dass jetzt EOF erreicht ist. Denn das Setzen des EOF-Bits, was "zu spät" gemacht wird, bewirkt schon direkt das Werfen der Exception. Keine Chance, vorher eof() zu fragen, um die Exception zu verhindern.

    und dann zum Format thema:

    <Configuration>
    <name>Hanswurst</name>
    </Configuration>
    
    Configuration
    {
        name: "Hanswurst"
    }
    
    configuration
    begin
      name := 'Hanswurst'
    end
    

    is doch wirklich jacke wie Hose, welches Format die daten haben. wenn der eine das eine Format besser findet, soll er die andren links liegen lassen. Wichtig ist meiner meinung nur, dass-egal welches Format die daten haben- die endverarbeitung gleich ablaufen kann.

    Du hast also zu dem Thema letztlich zu sagen, es sei egal, welches Format. Es wurden jetzt aber IMHO ein paar ganz brauchbare Argumente für XML genannt, falls es darum geht, ein menschen-lesbares und kompatibles Format geht. Egal ist es sowieso nie, es kommt auf den Anwendungsfall an. Ich kann ja auch mal ein effizientes binäres Format benötigen.



  • otze schrieb:

    vorwärtsseeken kannst du in jedem strom. und wenn die implementation von seak nur 2millionen mal get() aufruft ;). das rückwärtsseeken ist das problem.

    vorwärtsseeken = ignore. Sollte jeder vernünfitge Stream haben.

    otze schrieb:

    schau dir doch die streambuf objekte an, nur sie puffern. die istreams und ostreams puffern garnichts. Und wenn du es hasst,dass irgendetwas gepuffert wird, dann bleib ruhig und schreib folgende zeile:

    str.rdbuf()->pubsetbuf(NULL,0);
    

    das puffern ist immer optional.

    Ne der Puffer ist immer noch da, er hat nur eine Größe von 0. Dies schaltet seine Wirkung zwar aus allerdings muß noch jedes streambuf objekt ihn mit umher schleppen. Die IOStreams sollten ein Interface zur Verfügung stellen das sich nur um das Heranschleppen der Daten kümmert. Du kannst vielleicht davon noch eine Klasse ableiten welche einen Puffer an das Interface dran baut, dies wäre aber nicht mehr Teil von dem was ich als IOStream ansehe.

    otze schrieb:

    der größte vorteil ist:

    foo(iostream& str){
        str<<"eingabe:"
        int i;
        str>>i;
    }
    

    das funktioniert problemlos.

    folgendes nicht immer:

    foo(istream& in, ostream& out){
        out<<"eingabe:"
        int i;
        in>>i;
    }
    

    damit die funktion funktioniert müssen in und out aneinander gebunden sein. ansonsten muss du vor jeder eingabe flush() aufrufen.

    ansonsten spricht nichts dagegen:

    foo(istream& in, ostream& out){...}
    
    iostream str;
    foo(str,str);
    

    zu schreiben. mehr als 2 streams aneinanderketten und synchron halten tut iostream nämlich nicht.

    Dies ist in der Tat ein Problem das mir nicht bewußt war, danke. Allerdings ist es auch ein Problem, dass es soweit ich weiß kein iostream Objekt für die Console gibt. cout und cin allerdings in ein Objekt zu packen schafft aber mehr Probeme als es löst. Man könnte zum Beispiel die Ausgabe nicht mehr Program intern umleiten, da man die Bindung cin <=> cout nicht mehr aufheben kann. In der Form wie es im Moment vorliegt bin ich denoch der Meinung, dass es mehr Probleme schafft als es löst.

    otze schrieb:

    wozu? wenn du die streams benutzt, wirst du wohl wissen, was du erwartest. Und selbst wenn du nicht weist, was du erwartest, weist du normalerweise, wie groß der block "unbekannter Daten" ist. Wenn die eingabe kaputt ist, bleiben dir nicht viele möglichkeiten. mit kaputten daten kannst du nicht arbeiten. Entweder, es werden die daten dann neu angefordert, oder ne exception hat zu fliegen(wenn ne datei kaputt ist, kann man damit nicht mehr anständig weiterarbeiten. im besten fall kann man versuchen, die datei mit defaultwerten umzuschreiben).

    Zum Beispiel:

    [settings]
    age = 3
    title = "Hello"
    

    Hier ist es mir nicht bekannt welche Daten vorliegen, zu mindest nicht ohne dem Parser Zusatzinformationen über die möglicherweise enthaltenen Daten zu geben.

    otze schrieb:

    Und im fall unbekannter daten wirst du wohl nicht drumrumkommen, zu puffern. für sowas gibt es dann ja immernoch die stringstreams.

    Richtig erkannt und woher weiß ich wieviele Zeichen ich in den Stringstream laden muß? Zurück in den Stream schieben kann ich die möglicherweise zuviel gelesenen Zeichen ja nicht mehr.

    otze schrieb:

    is doch wirklich jacke wie Hose, welches Format die daten haben. wenn der eine das eine Format besser findet, soll er die andren links liegen lassen. Wichtig ist meiner meinung nur, dass-egal welches Format die daten haben- die endverarbeitung gleich ablaufen kann.

    Es ist Jacke wie Hose wenn die nötigen Metadaten die das Format braucht vorhanden sind. Ansonsten ist es nicht egal da nicht jedes Format machbar ist.

    EDIT: Ich sollte mal lernen zu quoten und die Vorschau zu benutzen


Anmelden zum Antworten