C++ ohne STL?



  • 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



  • Optimizer schrieb:

    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.

    ach, es geht hier um den stream internen exception mechanismus? dann halt ich mich doch besser raus^^. ich frag vor jeder lese operation eof ab, und werf dann ne exception...

    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.

    wie das format aussieht, ist ja auch schnurz. wenn der macher ein eigenes format vorsieht, kann er ja immernoch xml unterstützen, oder es ermöglichen, fremde formate einzubinden. Worauf ich hinaus will ist nur, dass jedes Format im endeffekt die gleichen Daten nur in einer anderen Form anbietet, sodass eine gewisse austauschbarkeit besteht.

    Wenn du als pro xml argument ansiehst, dass es ein bereits existenter standard ist, und man so weniger lernen muss, bring ich als gegenargument, dass jedes Programm das xml formate unterstützt auch mindestens eine art "syntax" vorsieht, die man lernen muss um für das programm einen auswertbaren input zu liefern. Sei es, wenn es auf XML basiert tagnamen, oder taganordnungen, attribute und werte, wertformate, etc pp.

    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.

    Mehr machen sie ja nicht. nirgendwo im standard steht, dass ein puffer puffern muss. die methode pubsetbuf kann ruhig nichts machen, wenn es nicht von vorteil ist. Dann muss man den puffer auch nicht mit rumschleppen, da der puffer selber nicht zum basisinterface gehört, und jede klasse die puffern will, einen eigenen puffer zu definieren hat, so sie ihn denn braucht.

    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.

    cin und cout sind aneinander gebunden! nur halt nicht durch den automatismus der iostream basisklasse, sondern rein von hand.

    hierzu: http://www.cplusplus.com/ref/iostream/ios/tie.html

    das iostream objekt selbst wird nr verwendet, wenn man ausdrücken will, dass zwei ströme wirklich fest miteinander verbunden sind. zb wenn man mit einem stream eine verbindung mit nem andren pc darstellt. Das ganze hat mehr symbolischen character als irgendwas sonst.

    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.

    da stellt sich natürlich die frage: kennt dein parser die form : bezeichner "=" wert? wenn er das kennt, dann liest er das so aus. an der Form der daten darf er eh nichts ändern. wenn er eigenständig suchen würde, welcher typ der passendste ist, kämst du in teufels küche, wenn der user als titel "1377" angibt. Dies ist immernoch sache des Programmierers, sicherzustellen, dass die daten valid sind.

    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.

    irgendeine info über die daten wirst du ja wohl haben müssen. Sei es anfangs oder ende zeichen, länge, form oder whatever. Und zurückschieben musst du garnix, wenn dus so einrichtest, dass etwaig zuviel gelesene daten im buffer zuerst wieder ausliest.



  • STL-User schrieb:

    Ein Prof. meinte neulich zu uns, dass C++ ohne die STL genauso gut für ressourcenschwache Architekturen geeignet ist wie C wenn ein passender Compiler vorhanden ist.

    Wie darf ich das jetzt verstehen - soll ich dann meine eigene String-Klasse aus char* bauen, meine eigenen Container+Speicherverwaltung? Wie ist das dann mit dem FileIO, basiert das nicht auch auf der STL? Muss ich dann meine eigenen Klassen aus den C-Funktionen bauen?

    mit "resourcenschwachen architekturen" meinte dein prof wohl computer zur steuerung von druckern,spülmaschinen etc. da brauchst du kein file i/o und windows gibts da (hoffentlich) auch keins.

    die frage ist hat, ob man c++ auch für embedded-systeme etc verwenden kann oder ob man da wieder auf c/asm zurück muß. natürlich kann man auch da mit c++ arbeiten und außerdem wird man für solche systeme natürlich eigene resourcenschonende betriebssysteme entwickeln.

    c++ an sich benötigt nur marginal mehr resourcen als c. das c++-programme unter windows fett sind liegt nicht an c++ sondern an den klassenbibiotheken und dem betriebssystem.



  • otze schrieb:

    wie das format aussieht, ist ja auch schnurz. wenn der macher ein eigenes format vorsieht, kann er ja immernoch xml unterstützen, oder es ermöglichen, fremde formate einzubinden. Worauf ich hinaus will ist nur, dass jedes Format im endeffekt die gleichen Daten nur in einer anderen Form anbietet, sodass eine gewisse austauschbarkeit besteht.

    Wenn du als pro xml argument ansiehst, dass es ein bereits existenter standard ist, und man so weniger lernen muss, bring ich als gegenargument, dass jedes Programm das xml formate unterstützt auch mindestens eine art "syntax" vorsieht, die man lernen muss um für das programm einen auswertbaren input zu liefern. Sei es, wenn es auf XML basiert tagnamen, oder taganordnungen, attribute und werte, wertformate, etc pp.

    Natürlich braucht man eine "Sprache", die von XML abgeleitet und damit auf das eigene Problem spezialisiert ist. XML ist praktisch nur ein Standard zur Beschreibung von Meta-Daten. Das ist immerhin schon mal eine Sache, die bereits erledigt ist und viel wichtiger, jeder XML-Parser kann auch meine Sprache parsen. Einen XML-Parser kriegt man irgendwo her und untersucht dann nur noch den Baum und das war's. Das ist halt ein Vorteil, den man verschenkt, zusätzlich kommt Zeitaufwand für die Überlegung eines eigenen Formats, insgesamt dann mit 0 Vorteilen. Ein theoretischer Geschwindigkeitsvorteil eines speziell angepassten Formats ist dabei in meinen Augen kein Vorteil, weil man bei gewissen Geschwindigkeitsanforderungen lieber gar nicht erst mit irgendeinem Text-Format arbeiten sollte. Amsonsten wurde bis jetzt kein Vorteil eines eigenen Text-Formats genannt.



  • kann man optimizer ernst nehmen?



  • ernst. schrieb:

    kann man optimizer ernst nehmen?

    um zu gucken, wie ernst man einen nehmen muß, guck besser selber, ob er seine thesen begründet. und versuch die gründe nachzuvollziehen.



  • otze schrieb:

    cin und cout sind aneinander gebunden! nur halt nicht durch den automatismus der iostream basisklasse, sondern rein von hand.

    hierzu: http://www.cplusplus.com/ref/iostream/ios/tie.html

    das iostream objekt selbst wird nr verwendet, wenn man ausdrücken will, dass zwei ströme wirklich fest miteinander verbunden sind. zb wenn man mit einem stream eine verbindung mit nem andren pc darstellt. Das ganze hat mehr symbolischen character als irgendwas sonst.

    cin und cout sind miteinander verbunden, das war mir klar. Allerdings hast du recht, dass eine Funktion die ein ostream und istream nimmt nicht davon ausgehen kann, dass die Streams miteinander verbunden sind. Dies heist sie kann nicht erwachten, dass die Daten die vom istream gelesen werden eine Reaction auf die nach ostream geschriebenen Daten darstellen. Bei iostream schon.

    otze schrieb:

    da stellt sich natürlich die frage: kennt dein parser die form : bezeichner "=" wert? wenn er das kennt, dann liest er das so aus. an der Form der daten darf er eh nichts ändern. wenn er eigenständig suchen würde, welcher typ der passendste ist, kämst du in teufels küche, wenn der user als titel "1377" angibt. Dies ist immernoch sache des Programmierers, sicherzustellen, dass die daten valid sind.

    Wieso ich in die Teufelsküche komme wenn ich den Parser bestimmen lasse, dass "1377" ein String ist sehe ich nicht. Ist doch eindeutig. 😕

    Desweiteren wäre es mit deiner Form eher

    bezeichner "=" wert "\n"
    

    Ich erweitere das Format um Strukturen:

    a = {
      b = 5
      c = 3
      d = 4
    }
    

    So das wars mit deiner Form. Dies zu parsen ist allerdings trivial wenn der Parser den Type mit bestimmt. Hier sogar sehr einfach möglich durch das lesen des ersten Buchstaben:

    • " => String
    • Ziffer => Zahl
    • { => Struktur
    • sonst was => Fehler

    Es ist aber nicht immer möglich durch das Lesen des ersten Buchstaben den Type zu bestimmen und dann muß man zurückseeken können um das noch irgendwie übersichtlich zu halten denn sonst muß man sämtliche Erkennungsfunktionen verschmelzen und unter Umständen kommt da ein kaum wartbares Monster raus. Viel einfacher ist da

    if(at number)
      read number;
    else if(at string)
      read string;
    else if(at block)
      read block;
    else
      error;
    

    Zwar unter Umständen leicht weniger effizient (nicht messbar) allerdings wahnsinnig viel übersichtlicher und wartbarer.

    Kann man natürlich noch um ein System erweitern das es erlaubt Types zu registriren und somit muß man Code gar nichts mehr ändern. In vielen Fällen wäre das aber meiner Meinung nach nicht nötig, kann man allerdings nicht allgemein sagen.

    otze schrieb:

    wenn dus so einrichtest, dass etwaig zuviel gelesene daten im buffer zuerst wieder ausliest.

    Ok vor jedes get/peek ein if(puffer leer) source.get() else puffer.get(). Desweitern wird es noch viel komplizierter wenn der Anfang des Wertes in dem Ende des Puffers liegt und das Ende der Wertes im Anfang des Stream. Viel Spaß beim Debuggen.



  • mag jetzt ein komischer vergleich sein aber wenn ich mir vorstell das spiele wie "tetris 3d" von irgendwelchen low budget herstellern 5-6 mal so große executables haben wie "half life 2" etc, dann lässt das einige vermutungen offen



  • otze schrieb:

    Wenn du als pro xml argument ansiehst, dass es ein bereits existenter standard ist, und man so weniger lernen muss, bring ich als gegenargument, dass jedes Programm das xml formate unterstützt auch mindestens eine art "syntax" vorsieht, die man lernen muss um für das programm einen auswertbaren input zu liefern. Sei es, wenn es auf XML basiert tagnamen, oder taganordnungen, attribute und werte, wertformate, etc pp.

    Ich denke, der eigentliche Vorteil von XML ergibt sich aus den "Erweiterungen" XSLT, XPath, XML Schema etc.

    Vor allem XSLT ist extrem praktisch. Wenn du von einer Syntax in eine andere konvertieren musst, musst du, wenn du ein Text- oder Binärformat hast immer einen Parser für den Input und den Output bauen.

    Mit XSLT baust du dir deinen Stylesheet, jagst den Code durch einen Prozessor und schon hast dein Format in (fast) jedes beliebige andere konvertiert. Vor allem bei Versionssprüngen im Dateiformat sollte das zur Vereinfachung beitragen.


Anmelden zum Antworten