Objekte erzeugen auf dem Stack oder auf dem Heap ?



  • Hallo zusammen,

    also vorab, ich hab die FAQs gelesen und auch die Suche benutzt, habe aber trotzdem noch ein paar Fragen wo ich noch Probleme mit habe:

    1. Gibt es eine Faustformel, wann Stack und wann Heap ? Also, z.B. bei X RAM Arbeitsspeicher sollte der Stack für Objekte nur bis 1/3 X RAM verwendet werden, wenn größer der Heap.

    2. Wie kann ich bei großen Objekten einfach feststellen/prüfen wieviel Speicherplatz sie beim Erzeugen verwenden ?

    3. Wenn ich prüfen will ob ein Objekt X schon erzeugt wurde (um es nicht ein 2. mal zu definieren), muss es ja vorher deklariert werden. Ist das richtig wenn ich das wie folgt mache:

    // Die Deklaration von X -> hat noch keinen Speicherverbrauch
    CKlasse *X = NULL;
    // ...
    // Hier wird X erzeugt, fall X noch nicht existiert
    if ( X == NULL ) X = new CKlasse();
    // ...
    // und hier wieder gelöscht
    delete X;
    X = NULL;
    

    Vielen Dank für Eure Hilfe.

    WoWe



  • WoWe schrieb:

    2. Wie kann ich bei großen Objekten einfach feststellen/prüfen wieviel Speicherplatz sie beim Erzeugen verwenden ?

    sizeof( Objekt )
    

    WoWe schrieb:

    ...(um es nicht ein 2. mal zu definieren)...

    Ansich wär dafür ein Singleton recht nett 😉



  • Also mit sizeof( X ) bekomme ich "4" zurück geliefert, habe aber min. 8 int in dem Objekt.

    Kannst du das mit dem Singleton etwas näher erläutern ?

    Danke und Gruß

    WoWe



  • sizeof( *Zeiger )
    


  • Danke,

    damit sieht der Wert realistisch aus.

    Kannst du auch was zu Singleton und meinem Beispiel sagen ?



  • WoWe schrieb:

    Kannst du auch was zu Singleton und meinem Beispiel sagen ?

    CKlasse& getTheOneAndOnlyCKlasse(){
       static CKlasse x;
       return x;
    }
    //und wer es braucht, macht
    getTheOneAndOnlyCKlasse().methode();
    

    das objekt wird erst angelegt, wenn es zum ersten mal gebaraucht wird und wird automagisch nach der main() gelöscht.



  • Hallo Volkard,

    danke für deine Hilfe. Das bringt mich zwar i.M. noch nicht weiter, aber ich hab zumindst was zum Googlen 🙂



  • WoWe schrieb:

    Hallo Volkard,

    danke für deine Hilfe. Das bringt mich zwar i.M. noch nicht weiter, aber ich hab zumindst was zum Googlen 🙂

    dann google gleich nach meyers-singleton
    der meyers-singleton ist der gebräuchlichste, aber es gibt noch nen haufen mehr. wenn du den kennst und der nicht so passt, sag genau, was du brauchst, dann frickeln wir einen zusammen.



  • Hallo volkard,

    Was gibt es denn noch für Singletons?

    Ist Meyers-Singleton threadsicher oder kann da theoretisch
    (natürlich nur beim 1. Aufruf) Konflikte entstehen?

    Gruß,
    Dennis



  • Singleton schrieb:

    Hallo volkard,
    Was gibt es denn noch für Singletons?

    nen ganzen haufen hat alexandrescu in modern c++ design gezeigt.

    Ist Meyers-Singleton threadsicher oder kann da theoretisch
    (natürlich nur beim 1. Aufruf) Konflikte entstehen?

    da kann ein konflikt entstehen.
    natürlich kann man den wiederum mit men mutex abfangen. und den mutex verbilligt man mit nem atomaren nachguck auf nen int um den mutex. oder man tutu threadlokal die referenz auf das objekt cachen. oder, was mein liebling ist, man erzwingt die erzeugung einfach vorher mit

    namepace{
    CKlasse& theOneAndOnlyCKlasse=getTheOneAndOnlyCKlasse();
    }
    

    innerhalb der Klasse.h



  • Oder man macht kein meyers-singleton, sondern so:

    class CKlasse
    {
      private:
        CKlasse() { }
        ~CKlasse() { }
        CKlasse& operator= (const CKlasse&) { }
      public:
        static CKlasse& getInstance();
    };
    
    CKlasse& getInstance()
    {
      static CKlasse* instance = 0;
      static Mutex mutex;
      if (instance == 0)  // erst ohne lock prüfen
      {
        Lock lock(mutex);
        if (instance == 0)  // jetzt mit lock prüfen, ob sich inzwischen was geändert hat
        {
          // hier sind wir jetzt exklusiv
          instance = new CKlasse();
        }
      }
      return *instance;
    }
    

    Das minimiert die Locks und man hat selbst Kontrolle über die Instantiierung. Ist bei Alexandrescu beschrieben.

    Die ganze Sache mit dem privaten Konstruktor, Destruktor und Zweisungsoperator hat den Sinn, daß der Compiler schon meckert, wenn man versucht, eine Instanz selbst anzulegen. Das kann schon mal versehentlich passieren, wie z. B.:

    CKlasse instanz = CKlasse::getInstance(); // geht nicht, da Zuweisung privat ist
    

    so geht es aber:

    CKlasse& instanz = CKlasse::getInstance();
    

    Ein Nachteil hat das ganze: Die Klasse wird nie zerstört. Aber das will man ja eigentlich auch gar nicht. Das fällt aber auf, wenn man einen Memory-leak-debugger nutzt. Der bemängelt, daß die Instanz nach Programmende nicht freigegeben wurde.

    Tntnet


  • Mod

    tntnet schrieb:

    Oder man macht kein meyers-singleton, sondern so:

    Das minimiert die Locks und man hat selbst Kontrolle über die Instantiierung. Ist bei Alexandrescu beschrieben.

    Die ganze Sache mit dem privaten Konstruktor, Destruktor und Zweisungsoperator hat den Sinn, daß der Compiler schon meckert, wenn man versucht, eine Instanz selbst anzulegen. Das kann schon mal versehentlich passieren, wie z. B.:

    CKlasse instanz = CKlasse::getInstance(); // geht nicht, da Zuweisung privat ist
    

    so geht es aber:

    CKlasse& instanz = CKlasse::getInstance();
    

    Ein Nachteil hat das ganze: Die Klasse wird nie zerstört. Aber das will man ja eigentlich auch gar nicht. Das fällt aber auf, wenn man einen Memory-leak-debugger nutzt. Der bemängelt, daß die Instanz nach Programmende nicht freigegeben wurde.

    Tntnet

    leider ist auch das nicht thread-safe. der zeiger instance sollte auf jeden fall extern linkage haben. nur dann kann man argumentieren, dass das erstellen eines Lock objekts potentiell auswirkungen auf seinen zustand hat (und so den compiler daran hindern, den code so zu transformieren, dass etwa das zweite if vor dem lock steht). das andere - wesentlichere - problem ist die sichtbarkeit von veränderungen an instance. ohne ein geeignetes speichermodell, das C++ gegnwärtig nicht hat, ist dieses problem prinzipiell nicht allgemein lösbar. die tatsache, das so etwas auf single-prozessor-systemen oder typischen multicore-pc-systmen funktioniert, bedeutet nicht, das diese konstruktion an sich sicher ist.

    Edit: es müßte genügen, instance volatile zu machen, anstatt ihm extern linkage zu geben. zwar ist der einzige weg, auf instance zuzugreifen, der aufruf von getInstance(), aber genau das könnte der Lock-Konstruktor ja tun. und da zugriffe auf volatile variablen und die reihenfolge dieser zugriffe beobachtbar sind; genügt das, um die beschriebene umordnung zu verhindern (vorausgesetzt, der compiler bekommt bestimmte teile des codes von Lock nie zu sehen). Ein anderes problem ist Mutex. Da es sich vermutlich nicht um ein POD handelt, wird der compiler die initialisierung erst beim ersten aufruf initialisieren. aber wann ist denn der erste aufruf, wenn die funktion aus mehreren threads aufgerufen wird ? 😉


Log in to reply