new operatoren



  • Ich habe eine gewisse Klassenhierarchie und möchte für eine Kindklasse Speicher reservieren ohne dabei den Konstruktor aufzurufen.
    Dann will ich mir die Adresse für die Basisklasse merken
    und schliesslich den Konstruktor für meine Kindklasse aufrufen.

    #include <iostream>
    using namespace std;
    
    class A
    {
      public:
        A() : x( 1 ){
          cout << "class A created" << endl;
        }
        ~A(){
          cout << "class A deleted" << endl;
        }
        int x;
    };
    
    class B : virtual public A
    {
      public:
        B(){
          cout << "class B created" << endl;
        }
        ~B(){
          cout << "class B deleted" << endl;
        }
        int y;
    };
    
    int main( int c, char** v )
    {
      // Speicher fuer B anlegen
      long s = sizeof( B );
      A* a = (A*)operator new ( s );
      cout << "addr a: " << a << endl;
      cout << "x: " << a->x << endl;
      // Konstruktor fuer B aufrufen
      B* b = new (a) B;
      cout << "addr a: " << a << endl;
      cout << "addr b: " << b << endl;
      cout << "x of a: " << a->x << endl;
      cout << "x of b: " << b->x << endl;
    }
    

    Ausgabe

    addr a: 0x8a9e008
    x: 0
    class A created
    class B created
    addr a: 0x8a9e008
    addr b: 0x8a9e008
    x of a: 134515940
    x of b: 1
    

    Warum ist x of a nicht auch 1?
    Das muss irgendwas mit dem virtual zu tun haben... aber was?


  • Mod

    Nach der Konstruktion von B steht keinesfalls fest, dass dein Zeiger a auf das A-Subobjekt zeigt, im Falle von virtueller Vererbung wie hier ist das nicht einmal wahrscheinlich.
    Gib doch mal

    cout << "addr (A*)b: " << (A*)b << endl;
    

    aus.



  • Erstens: Der Unterschied liegt vermutlich an internen Verwaltungsdaten für die virtuelle Vererbung. Wenn du dir die Adresse des A-Anteils in b auch noch ausgeben lässt, erkennst du den Unterschied.
    Zweitens: Was soll dieses Gebastel überhaupt erreichen? Wie du siehst, werden die Konstruktoren trotzdem beide aufgerufen.



  • Was passiert, wenn bei der Konstruktion eines Objekts mit new im Konstruktor eine Exception geworfen wird?

    Ist der Speicher dann noch da, oder wird der automatisch aufgeräumt?



  • new räumt hinter sich auf, wenn bei der Konstruktion des Objekts etwas schiefgegangen ist. (afaik schließt das auch ein, daß fertig konstrierte Teil-Objekte wieder sauber zerstört werden)



  • CStoll schrieb:

    (afaik schließt das auch ein, daß fertig konstrierte Teil-Objekte wieder sauber zerstört werden)

    Jap, das ist immer garantiert, nicht nur wenn das Objekt mit new erzeugt wurde.


  • Mod

    matti83 schrieb:

    Was passiert, wenn bei der Konstruktion eines Objekts mit new im Konstruktor eine Exception geworfen wird?

    Ist der Speicher dann noch da, oder wird der automatisch aufgeräumt?

    Wenn ein new-Ausdruck wegen einer Exception, die in einem Konstruktor geworfen wird, fehlschlägt, geschehen 2 Dinge:
    1. Zuerst werden im Falle eines Array-new alle zuvor erfolgreich konstruierten Elemente in umgekehrter Reihenfolge zerstört.
    2. Danach wird die zur jeweiligen Allokationsfunktion zugehörige Deallokationsfunktion aufgerufen. Abgesehen vom expliziten Aufruf dieser Funktionen ist das überhaupt der einzige Fall, in dem placement-delete-Funktionen ausgeführt werden, ein normales delete ruft ja immer die Standardform
    void operator delete(void*) bzw. void operator delete[](void*) auf (welche Funktion genau hängt bei klassenbezogener Überladung allerdings ggf. vom dynamischen Typ des Objektes ab). Die Standardform der placement-delete-Funktion tut nichts.



  • Okay. Danke... dann kann ich erstmal weiter testen 👍


Log in to reply