Resourcenproblem mit std::stringstream



  • @pumuckl:

    okay ... und mit welchen tools bzw. librarys könnte ich das noch besser untersuchen ?

    ... und stimmst du mir nicht bei der Antwort an Artchi zu ?

    @Artchi

    Ich denke nicht, das RVO in meinem beschriebenen Fall angewendet wird... das std::string objekt hat doch eher eine kleine größe und beinhaltet einen pointer, an dem der alokierte Speicher hängt ... RVO wird doch nur bei großen Objekten einer Klasse verwendet ... oder nicht ?



  • ...ich habe auch noch geantwortet, für den Fall, dass du das übersehen hast. 🙂



  • Wer sagt denn eigentlich, dass stringstream intern einen std::string verwendet? Er kann da auch ein simples char-Array (passend zu den traits) haben. Dann wird der string erst bei Aufruf von str() erzeugt. Das kann dann natürlich optimiert werden.



  • Braunstein schrieb:

    Dann wird der string erst bei Aufruf von str() erzeugt.

    So wie ich pro_develop verstanden habe, ist das genau sein Problem. Ob man von einem std::string oder char* eine Kopie erstellt, spielt schlussendlich keine so grosse Rolle. Es braucht beides Speicher und Rechenzeit, mit denen er sparsam umgehen wollte. 😉

    Braunstein schrieb:

    Das kann dann natürlich optimiert werden.

    Optimiert werden können auch hier wieder nur unnötige temporäre Kopien.

    std::stringstream Stream;      // mit 1 MByte füllen
    DoSomething(Stream.str());     // kopiert mindestens einmal 1 MByte
    


  • @Nexus:

    Habe deine umfangreiche Antwort natürlich nicht übersehen 🙂

    Ich habe mich auch bei den letzten Antworten falsch ausgedrückt ... ich meinte, dass RVO nur bei großen Objekten einer Klasse als Rückgabewert einen effektiven Nutzen haben dürfte... und dass ich nicht glaube, dass die Umsetzung von RVO so komplex ist, dass auch dynamisch alokierte Objekte von RVO gehandelt werden ....

    Ich verstehe auch einfach nicht das Prinzip, nach dem der C++ Standard die stringstreams umsetzt ... bei einer Datei oder den E/A-Geräten kann ich doch auch direkt etwas auf dem Bildschirm dazwischen ausgeben ... oder wenn ich auf die datei zugreifen möchte, dann muss ich doch auch nicht erst eine kopie erstellen ... ?

    Das mit der Datenkapselung ist schon richtig, aber es könnte doch wenigstens einen offiziellen Weg geben, um an die Adresse des internen string-Objekts zu gelangen um ggf. Zugriff auf die eigentlichen Rohdaten zu bekommen.

    Ich finde das einfach nicht durchgängig von der Umsetzung her ... gibt es bei dem C++ Gremium, das den Standard festlegt, soetwas wie ein Verbesserungsvorschlagswesen ? Hat da jemand Kontakte ? 😉



  • @Braunstein:

    Ich dachte das ist nur in std::strstream ein char Array ...

    In einem Artikel hatte ich gelesen, dass der Standard ein std::string Objekt für std::stringstream verwendet ...

    Ist die Info in dem Artikel etwa falsch ???



  • Wenn ich den Standard richtig lese, ist die interne Representation der Daten in stringstream nicht festgelegt. Es wird lediglich verlangt, dass mit einem basic_string initialisiert werden kann und dass eine Funktion zur Rückgabe eines solchen existiert.



  • pro_develop! Da hast du etwas falsch verstanden. Nehmen wir mal die Filestreams von C++. Auch dort entstehen natürlich Kopien, der Daten:

    ofstream f("datei.txt");
    f << "Hallo"; // landet im Stream-Puffer, ein gekapselter Speicherblock
    f.flush(); // eine Kopie des Stream-Puffers landet im Dateisystem (z.B. Festplatte)
    

    Bei allen Outputstreams schiebst du Daten rein, und die werden am Ende irgendwo als Kopie landen müssen. Gerade wegen der Kopiererei sind die meisten Streams gepuffert! Und ohne Puffer wäre es wohl noch langsamer, weil dann jedes Byte einzeln kopiert werden müsste, anstatt der effizienteren blockweisen Kopie (so groß wie der Puffer halt).

    Selbst die Ausgabe mit cout bedingt eine Kopie der Daten auf dem Bildschirmspeicher oder Terminal oder wie auch immer. Wenn durch flush() was in der Konsole oder Festplatte erscheint, ist es vergleichbar mit dem str() .

    Das die Streams einen Direktzugriff erlauben, kann ich nicht erkennen. Kannst du vielleicht eine Methode vom fstream nennen?

    Zu dem Gremium: das ist die WG21 Group. Und natürlich kann jeder dort seine Vorschläge einreichen (das Gremium bittet sogar darum!). Du kannst sogar an den Meetings persönlich als Zuschauer teilnehmen, die freuen sich wenn es Interessenten gibt. 🙂 Eine Anlaufstelle kann die Newsgroup news://comp.lang.c++.moderated sein, da lesen und schreiben die meisten aus dem Gremium mit.
    Tip: http://magazin.c-plusplus.net/artikel/Der CPlusPlus-Standardisierungs-Prozess



  • @Nexus:

    Danke für deinen Lösungsvorschlag 🙂

    ... da hab ich zu schnell auf "senden" gedrückt ... ich wollte doch noch auf deinen Lösungsvorschlag eingehen ...

    ... wenn ich zwischen dem stream und dem string objekt häppchenweise kopiere, dann habe ich doch aber das Problem mit dem allokierten Speicher nicht umgangen ??? ...

    wenn meine Datei 100 MB groß wird, dann müsste ich doch mit string.reserve() die ganzen 100 MB allokieren ... oder wie hast du das gemeint ?

    und der stream verringert ja auch nicht automatisch seine Größe, wenn ich in kleinen Stücken daraus lese ... ich könnte den stream doch erst zum Schluß dealokieren ... oder ?



  • pro_develop! Warum benutzt du denn stringstream ? Wenn du problemlos string nutzen kannst, war stringstream eh die falsche Klasse. Denn normalerweise erfüllen beide Klassen unterschiedliche Zwecke.



  • @Artchi:

    du hast nicht verstanden wie ich das meine 😞 ... ich versuch es noch einmal zu erklären ...

    wenn du einen File-Stream erzeugst, dann gibst du eine vorhandene, greifbare Datenquelle, also die auf der Platte vorhandene Datei an ... auf diese Rohdaten in der Datei kannst du auch auf anderen Wegen zugreifen ...

    Bei den String-Streams kannst du eine vorhandene Datenquelle angeben, auf die ein freier Zugriff existiert ... es wird jedoch intern eine Kopie erstellt und damit geht der Zugriff auf die vom Stream bearbeiteten Daten verloren ... im Gegensatz zu einer Datei ...



  • Und im Zweifelsfall kannst du dir immmernoch eine eigene Streamklasse schreiben, die exakt auf deine Anforderungen zugeschnitten ist. 😃



  • pro_develop schrieb:

    @pumuckl:

    okay ... und mit welchen tools bzw. librarys könnte ich das noch besser untersuchen ?

    Die Tools heißen allgemein Profiler, mit denen kannst du Performance- und Ressourcenverbrauch untersuchen.



  • Artchi schrieb:

    pro_develop! Warum benutzt du denn stringstream ? Wenn du problemlos string nutzen kannst, war stringstream eh die falsche Klasse. Denn normalerweise erfüllen beide Klassen unterschiedliche Zwecke.

    siehe Anfangsproblematik ... ich generiere einen Stream mit der zur Verfügung stehenden Formatierung der Daten und muss dann einer Bibliotheksmethode eine Referenz auf std::string übergeben ...



  • pro_develop schrieb:

    siehe Anfangsproblematik ... ich generiere einen Stream mit der zur Verfügung stehenden Formatierung der Daten und muss dann einer Bibliotheksmethode eine Referenz auf std::string übergeben ...

    Aha! Also kannst du doch nichts mit string anfangen. Denn zum Formatieren ist string nicht fähig. D.h. du mußt mit einer nicht- string -Klasse erstmal eine Zeichenkette formatieren, richtig? Egal wie du das anstellst, du wirst string dafür nicht nutzen können.

    Wie willst du also eine Kopie der formatierten Zeichnkette vermeiden? 😃

    Dir bleibt nichts anderes übrigig, als einen eigenen stringstream zu implementieren oder Algorithmen (freie Funktionen), und bei der Übergabe des Strings an den Ctor die Endgültige Größe zu kennen:

    // PSEUDO CODE!
    
    class stringstream
    {
        std::string &sref; // entscheidender Punkt!
    
    public:
        stringstream(std::string &s) : sref(s) {}
    
    // I/O Operatoren........
    };
    
    // ==========================================
    
    int main()
    {
     std::string s(10000, ' '); // String wird 10.000 Zeichen enthalten
    
     stringstream st(s);
     // irgendwas formatieren...
    
     foo(s);  // fremde Funktion, die einen std::string fordert
    }
    

    Dann würden die Operatoren direkt den referenzierten String manipulieren. Und damit sich das ganze auch rentiert, darf in dem oberen Beispiel der String keine 10.000 Zeichen übersteigen, weil sonst schon eine Kopieraktion im string nötig wäre - die du eigentlich vermeiden willst.

    Auch dürfen die Operatoren nur Zeichen im String manipulieren, aber keine zus. hinzufügen, da sonst eine Kopieraktion in string droht.

    Also ohne Profiler würde ich da keinen Finger für krumm machen... weil sonst ist alles für die Katz gewesen. 🙄



  • @Artchi:

    ich hab doch nicht gesagt, dass ich etwas mit sring formatieren will ... ??? *verzweifel*

    siehe Anfangsproblematik ... ich generiere einen Stream mit der zur Verfügung stehenden Formatierung der Daten und muss dann einer Bibliotheksmethode eine Referenz auf std::string übergeben ...

    ich schreibe in einer Schleife in den stringstream ...

    hugo << hex << var_a << endl;
    

    und damit wächst der in std::stringstream enthaltene std::string kontinuierlich an bis er z.B. 100 MB groß ist ...

    und dann möchte ich eine Library verwenden, die den std::string parst, ohne beim erzeugen des std::string Objekts eine Speicherbelgung von 200 MB zu benötigen ...



  • Also du moechtest 100 MB an Text parsen ... wieviel Buecher das wohl sind? Kann das Parsen nicht in kleine Teile zerlegt werden?



  • klingt ja stark als ob der op strstream suchen würde...



  • Shade Of Mine schrieb:

    klingt ja stark als ob der op strstream suchen würde...

    strstream ist meines Wissens deprecated. Also nicht gerade zukunftssicher. Aber selbst wenn, hilft das dem OP auch nicht weiter.



  • pro_develop schrieb:

    @Artchi:

    ich hab doch nicht gesagt, dass ich etwas mit sring formatieren will ... ??? *verzweifel*

    Ist mir schon klar. Du hast nur nicht verstanden, wohin ich dich führen will. (sie unten letzter Absatz) Anscheinend hast du dich da in etwas verbissen, und du bist hier der einzige ... sonst wären wir nicht auf Seite 3.

    pro_develop schrieb:

    ich schreibe in einer Schleife in den stringstream ...

    hugo << hex << var_a << endl;
    

    und damit wächst der in std::stringstream enthaltene std::string kontinuierlich an bis er z.B. 100 MB groß ist ...

    Wer sagt denn das im stringstream ein string drin ist? 🙄 Das ist doch ein Implementierungsdetail, das dir am A**** vorbei gehen sollte! Denk doch einfach erstmal abstrakt. Ist zwar erstmal schwer zu lernen, aber das muß man auch lernen - abstrakt denken.

    pro_develop schrieb:

    und dann möchte ich eine Library verwenden, die den std::string parst, ohne beim erzeugen des std::string Objekts eine Speicherbelgung von 200 MB zu benötigen ...

    Wer garantiert dir das 200 MB belegt werden? Kann garnicht gehen.
    1. weil ein stringstream nicht mit einem string implementiert sein muß.
    2. wenn es mit einem string implementiert sein sollte, könnte string so implementiert sein eine interne Refernzzählung zu betreiben. So das zwar ein zweites string-Objekt da wäre, aber das zweite string-Objekt intern auf die Zeichenkette vom ersten string-Objekt verweist!
    3. du könntest auch den stringstream in einen Scope einschränken, so das (falls wirklich der Fall) die 200 MB nur kurzzeitig belegt sind. Beispiel:

    const std::string format()
    {
         stringstream s;
         // formatierung
         return s.str(); // RVO
    }
    
    void foo()
    {
        libfunction(format());
    }
    

    Aber ganz ehrlich? Ich weiß nicht was du willst? Weil einerseits mit stringstream formatieren wollen, andererseits einen string übergeben wollen... ist paradox, keine Datenkopie zu haben.


Anmelden zum Antworten