Frage zu C++-Standard: Speicherbereiche und Zeigervergleichungen



  • Hi, ich habe folgenden Code:

    #include <iostream>
    using namespace std;
    
    struct Foo *foo_ptr;
    struct Bar *bar_ptr;
    
    struct Foo
    {
    	Foo() { foo_ptr = this; }
    };
    
    struct Bar
    {
    	Bar() { bar_ptr = this; }
    
    	char dummy0[24];
    	Foo foo;
    	char dummy1[43];
    };
    
    int main ()
    {
    	Bar bar;	
    	assert((char*)foo_ptr >= (char*)bar_ptr);
    	assert((char*)foo_ptr <= (char*)bar_ptr + sizeof(Bar));
    }
    

    Ich teste also, ob sich die Addresse eines Members in einer Instanz immer im Bereich [&instanz, &instanz+sizeof(instanz)] befindet.

    Sind die Zusicherungen immer erfuellt?
    Darf ich ueberhaupt die Zeiger so vergleichen?

    Hintergrund: Ich will herausfinden, ob ein Objekt ein Member eines anderen Objekts ist. Wenn das so moeglich ist, koennte man so einen smarten GC-Pointer basteln, der eine echte GC und nicht nur Referenzzaehlen bieten (Mark&Sweep etc).

    -Gunnar



  • Nun, ich denke im Prinzip funktioniert obiger Test, weil es wohl überall so sein wird. Aber garantiert und damit standardkonform ist es vermutlich nicht.

    Außerdem dürfte es mit der Vererbung schwierig werden.

    MfG Jester



  • Wenn ich denke was Du bzg. Vererbung denkst, liesse sich das durch Ueberladen der globalen new/delete-Operatoren loesen, indem man einfach die angeforderten Speicherbereiche protokolliert. Dann benoetigt man kein sizeof mehr.

    Ich dachte mir das so:

    struct GCDummy {};
    
    void *operator new(size_t s, GCDummy &gc)
    {
      // speicherbereich protokollieren
    }
    
    // (das selbe fuer delete)
    
    #define GC (GCDummy())
    
      // z.B.:
      Foobar *fb = new GC Foobar(..);
      // ...
    

    Diese Zeiger koennen nun in einem smarten GC-Pointer benutzt werden (normale Zeiger sind dann wie gehabt weak-Pointer).

    template <class T>
    void destruct(void *obj)
    {
      delete static_cast<T*>(obj);
    }
    
    template <class T>
    class gc_ptr
    {
      T *ptr;
    
    public:
      gc_ptr(const T* ptr)
      {
        // 1. Pruefe ob ptr ein heap-objekt ist (Nein -> Exception)
        // 2. Pruefe ob 'this' in einem heap-objekt (das mit new GC angefordert wurde) liegt
        // 3a. Ja? Dann wird ptr von diesem Objekt referenziert (das wird irgendwo abgespeichert)
        // 3b. Nein? Dann ist ptr ein root-node (gilt als immer erreichbar)
        // 4. Auch die Addresse von 'destruct<T>' (siehe oben) wird abgespeichert, damit das Objekt hinterher ordentlich zerstoert werden kann.
      }
    
      // hier die ueblichen Operationen
    
    };
    
    // Dann ist der Mark&Sweep-Algorithmus trivial zu implementieren (??)
    

    So ungefaehr. Was meint ihr, koennte das so funktionieren?

    -Gunnar


Anmelden zum Antworten