Speicherverbrauch shared_ptr und normaler *



  • booster schrieb:

    Doch etwas komplizierter. Es ist keine Flache map. Sondern die gespeicherten Objekte haben wiederum eine map mit Objekten gleichen typs. Hier wiederum benötige ich den Zeiger auf das Elternelement.

    D.h. du baust shared_ptr Zyklen. shared_ptr kann aber keine Zyklen freigeben. => Leak.

    EDIT: OK, das wurde ja schon geschrieben.



  • ok aber anstelle meiner shared_ptr für parent usw. könnte ich ja dann wie erwähnt weak_ptr benutzen. Und auch als Rückgabe meiner find Methode oder?



  • Vorschlag: Ownership per vector<unique_ptr<T>> . Dazu die ganzen Maps mit einfach T* als Wert.
    Done.

    Also quasi

    class MyBagOfThings {
        // ...
    private:
        std::vector<std::unique_ptr<Thing>> m_things;
        std::map<Key, Thing*> m_index;
    };
    

    Oder übersehe ich was?



  • Schlangenmensch schrieb:

    Generell shared pointer zu verwenden, schön Referenzen mitzählen und sich halt keine Gedanken um Ownership zu machen ist ein einfacher Weg aber kein schöner.

    ... sagt wer? Ich finde einfache Wege per se schön. So schön, dass ich nach komplizierteren erst bei eindeutig festgestelltem Bedarf suche.

    Der sauberste Weg hier, wäre wahrscheinlich ein Iterator auf das Map Element rauszugeben ...

    Nein. Es ist sogar äußerst unsauber, jemandem, der lediglich ein Objekt anfragt, einen Iterator zu schenken, denn:
    1. will derjenige gar nicht den Iterator, sondern nur das, was in iterator->second steckt.
    2. geht es ihn nichts an, dass es sich um eine Map handelt. Gibt man dieses Wissen öffentlich bekannt, kann man den Container nicht mehr ohne weiteres ändern.
    3. bekommt derjenige damit die Macht, nicht nur das gewünschte Objekt abzuholen, sondern Stück für Stück den ganzen Containerinhalt.



  • booster schrieb:

    ok aber anstelle meiner shared_ptr für parent usw. könnte ich ja dann wie erwähnt weak_ptr benutzen. Und auch als Rückgabe meiner find Methode oder?

    Wenn du mit weak_ptr arbeitest muss du halt immer mit lock() ein shared ptr erzeugen, wenn du mit dem Pointer arbeitest.



  • Um es noch einmal zusammenzufassen:
    Es gibt mehrere gangbare Wege. Welcher davon der richtige und für deinen Zweck beste ist, musst du selbst entscheiden, da wir deinen Anwendungsfall nicht genug kennen. Im übrigen stellen wir deswegen einfach mal die gesamte Datenstruktur in Frage 😉



  • booster schrieb:

    ok aber anstelle meiner shared_ptr für parent usw. könnte ich ja dann wie erwähnt weak_ptr benutzen.

    Ja, weil du sonst geschlossene Referenz-Kreise baust. Das ist der Grund, weshalb es weak_ptr gibt.

    Und auch als Rückgabe meiner find Methode oder?

    Wozu soll das gut sein? Die Map hält einen shared_ptr, find erzeugt einen weak und reicht den raus, und der Empfänger muss erst mal wieder einen shared draus machen, um damit was anfangen zu können?



  • @printe
    du teilst also jedes mal wenn du einen pointer raus gibst gleich die kompletten Besitzverhältnisse?
    Ein shared_ptr ist nicht einfach nur mal eben einen counter incrementieren. Da steckt ein gewisser sync overhead drin, der nicht zu verarchten ist.



  • OT

    Schlangenmensch schrieb:

    Generell shared pointer zu verwenden, schön Referenzen mitzählen und sich halt keine Gedanken um Ownership zu machen ist ein einfacher Weg aber kein schöner.

    Diese Kritik hört man oft.

    Lustigerweise habe ich in 20 Jahren Arbeiten mit C++ mehr Probleme erlebt die dadurch verursacht wurden dass auf shared_ptr verzichtet wurde als Probleme die von übertriebenem shared_ptr Einsatz kamen.

    Und jedes mal wenn ich "keine Gedanken um Ownership zu machen" als quasi Argument gegen shared_ptr lese denk' ich mir meinen Teil.

    /OT



  • ps:

    booster schrieb:

    4. Ist eine std::map wirklich der richtige Container für deinen Usecase?
    Ich benötige die map mit einem string als Key um nach bestimmten Objekten zu suchen. Denke schon, das hier map das richtige ist.

    Alternativen könnten sein:
    std::unordered_map
    boost::flat_map



  • Spart die std::unordered_map platz.

    Aber bevor wir noch lange über Pointer reden. Habe den Platzverbraucher gefunden.

    Die Daten selbst bestehen aus 9 Variablen. Darunter sind 4 strings.

    Früher waren die strings CStrings von MFC. Nun habe ich diese unter anderem auch auf std::strings umgestellt.

    sizeof(CString) = 4
    sizeof(std::string) = 28

    Bei 4 strings sind das 96 Bit mehr.
    Bisher 56 bits nun 152. Das ist natürlich das dreifache. Und mein erhöhter Speicherverbrauch erklärbar. An der falschen Stelle gesucht. Aber nun was über smart pointer gelernt.


  • Mod

    Leider hast du aber überhaupt nichts über strings gelernt und guckst daher an der völlig falschen Stelle. Denk mal drüber nach, wie so ein String wohl funktioniert. Wenn ich da "12345" drin speichere, wie kommt der dann mit 4 Bytes aus?

    Und dir sollen wir nun einfach glauben, dass deine Datenstruktur so richtig ist, bloß weil du uns das sagst 🙄



  • Wieso soll nun meine Datenstruktur nicht stimmen. Was hat das nun mit dem string zu tun?????

    Kannst du auch mal ne Lösung geben als immer alles schlecht zu machen und einen zu kritisieren.

    Wenn ich siezof(myClass->mystring) aufrufe erhalte ich 4
    Wenn ich siezof(myClass->myCString) aufrufe erhalte ich 28

    und das egal wieviel in dem string steht.



  • Und das glaubst du? Wenn du in einem CString "Hello World" ablegst hat er auch nur eine Größe von 4 Byte? Oder sind diese 4 Byte möglicherweise nur ein Zeiger auf den Speicherbereich, wo die tatsächlichen Daten stehen?



  • dann helft mir doch mal auf die Sprünge

    wenn ich sizeof(myclass) mache erhalte ich in ersterem Fall 56
    und in zweiteren 152

    Wenn ich nun wieder auf CString umstelle lande ich wieder bei 1,2GB Speicherauslastung.

    Wo liegt dann das Problem



  • Dies nennt sich small string optimization (SSO), d.h. einige std::string Implementationen haben einen kleinen Puffer (ca. 16-20 chars) - u.a. beim MSVC.

    @booster: Was SeppJ und DocShoe dir sagen wollen, ist, daß sizeof(std::string) nur den statischen Speicherplatz angibt - zur Laufzeit wird dann (ohne SSO) der eigentliche String auf dem Heap reserviert.



  • DNKpp schrieb:

    @printe
    du teilst also jedes mal wenn du einen pointer raus gibst gleich die kompletten Besitzverhältnisse?

    Indem du einen Pointer rausgibst über ein öffentliches GetPointerToObject-Interface, teilst du den Besitz de facto, denn was der Empfänger damit anfängt, ist nicht mehr unter deiner Kontrolle. Also ist es nur richtig, wenn der Code das widerspiegelt. Ja, wenn ich Pointer rausgebe und nicht weiß, an wen, dann teile ich den Besitz (oder gebe ihn ganz ab, je nachdem).

    Wenn du Raw-Pointer verteilst auf Objekte, die du in Smartpointern verwaltest (egal ob unique oder shared), dann lügst du dir selber einen vor, denn die ganze Besitz- und Lebenszeitkontrolle, die in den Smartpointern steckt, stimmt nicht mehr.

    In einem lokalen, überblickbaren Kontext kann man shared_ptr::get gefahrlos verwenden. Aber nicht als Rückgabe an jeden X-beliebigen.



  • booster schrieb:

    dann helft mir doch mal auf die Sprünge

    wenn ich sizeof(myclass) mache erhalte ich in ersterem Fall 56
    und in zweiteren 152

    Wenn ich nun wieder auf CString umstelle lande ich wieder bei 1,2GB Speicherauslastung.

    Wo liegt dann das Problem

    Das Problem ist, dass das den Speicherverbrauch eben nicht erklärt. Rechne doch selber nach:

    56 Bytes pro Objekt mal 1 Million Objekte = 56 MB. Das ist Lichtjahre von 1,2 GB entfernt. Für 152 Bytes pro Objekt gilt das gleiche.

    Dein Speicherproblem muss eine andere Ursache haben.

    Was enthalten denn die 4 Strings, die MyClass enthält? Wie lang sind die Nutzdaten?

    Könnte es sein, dass die eine String-Implementierung 8-Bit-Zeichen benutzt und die andere breitere? Vergleich doch mal
    sizeof (myClass.myStdString[0]) und
    sizeof (myClass.myCString[0]).



  • Sind die Strings denn alle unterschiedlich? Kannst du eine Lookup-Tabelle benutzen und in deiner Datenstruktur nur einen Index statt des Strings speichern? Zeig doch bitte mal deine Struktur und schreib ein bisschen was dazu.

    @Printe:
    Du vergisst vermutlich die echten Stringdaten.


  • Mod

    booster schrieb:

    Wieso soll nun meine Datenstruktur nicht stimmen. Was hat das nun mit dem string zu tun?????

    Deine Beschreibungen waren allesamt falsch oder inkonsistent, alles deutet darauf hin, dass deine Datenstrukturen sowohl falsch gewählt als auch falsch umgesetzt sind. Doch du bestehst darauf, dass das natürlich alles richtig ist, denn es kommt von dir und alle anderen sind dumm, wenn sie es wagen, dich zu kritisieren. Und dann bringst du solche Dinge wie deine Beobachtung mit dem String, die zweifelsfrei beweisen, dass du absolut keine Ahnung von dem hast, wovon du hier sprichst. Da soll man deinen Versicherungen glauben, dass mit den Datenstrukturen alles in Ordnung sei? Du hast offensichtlich gar nicht die Kompetenz dies zu beurteilen.

    Wenn ich siezof(myClass->mystring) aufrufe erhalte ich 4
    Wenn ich siezof(myClass->myCString) aufrufe erhalte ich 28

    und das egal wieviel in dem string steht.

    Mitdenken tust du auch nicht. Denn sonst wärst du über diese Beobachtung vielleicht so langsam drauf gekommen, dass sizeof absolut nichts mit der Speicherbelegung durch ein Objekt zu tun hat. Schließlich hat deine map auch ein sizeof von wenigen Bytes, obwohl du dort mehrere Gigabyte Speicherbelegung vermutest (Betonung auf "vermutest", denn deinen Beobachtungen und Schlussfolgerungen kann man nicht mehr glauben).

    Kannst du auch mal ne Lösung geben als immer alles schlecht zu machen und einen zu kritisieren.

    Ach! Deshalb habe ich auch nur vor 5 Seiten schon geschrieben, was nötig ist, damit man dir helfen kann. Du hast nichts davon geliefert und machst stattdessen nur Leute dumm an, wenn sie dir helfen wollen. Ich klinke mich hier aus. Wer dir noch weiter helfen will, ist selber schuld!


Anmelden zum Antworten