[gelöst]Operator new: Aufruf über Funktionssyntax



  • Hallo zusammen,

    weiß jemand ob, und falls ja wie, es möglich ist den Konstruktor einer Klasse bei einem new Aufruf über die Funktionssyntax aufzurufen.

    Also sowas in der Art wie

    Test* foo = static_cast<Test*>(::operator new(sizeof(Test))) Test();
    

    Hier bekomme ich folgenden Fehler mit MSVC10

    error C2146: Syntaxfehler: Fehlendes ';' vor Bezeichner 'Test'
    

    Danke für die Hilfe
    Tobi



  • Test* foo = static_cast<Test*>(::operator new(sizeof(Test)));
    

    wäre korrekt. 😉



  • Hi Pi,

    danke für die Antwort.

    Leider wird hier aber nur Speicher reserviert. Mir geht es aber auch um den Konstruktoraufruf.



  • //Speicher besorgen:
    Test* foo = static_cast<Test*>(::operator new(sizeof(Test)));
    //Konstruktor aufrufen:
    foo = new(foo) Test(some_ctor_args);
    
    //freigeben umgekehrt, erst Dtor aufrufen:
    foo->~Test();
    //speicher freigeben:
    ::operator delete(foo);
    


  • pumuckl sagts schon



  • pumuckl schrieb:

    //Speicher besorgen:
    Test* foo = static_cast<Test*>(::operator new(sizeof(Test)));
    //Konstruktor aufrufen:
    foo = new(foo) Test(some_ctor_args);
    
    //freigeben umgekehrt, erst Dtor aufrufen:
    foo->~Test();
    //speicher freigeben:
    ::operator delete(foo);
    

    Hallo pumuckl,

    danke für die Antwort. Dass heißt ich muss also Placement new aufrufen und kann dass nicht mit dem Funktionsaufruf von new miterledigen?

    Weißt du wie dass der Operator new normalerweise macht wenn man Ihn über die Operator Syntax aufruft?

    Ich hab mein Effective C++ leider momentan nicht verfügbar.

    Test* foo = new Test();
    

    Dieser Aufruf verheiratet ja auch beides irgendwie. Und bisher dachte ich immer dass die operator syntax nur syntaktischer Zucker ist und der Funktionsaufruf equivalent ist... 😕

    Grüße
    Tobi



  • Statt

    new T();
    

    geht auch

    new T;
    

    😉

    Ist mir auch persönlich lieber, da nicht so Java-like.



  • Benutzerdefinierte new - und delete -Operatoren:

    void* operator new(std::size_t bytes, X customParam);
    void  operator delete(void* memory, X customParam);
    

    Der delete -Operator wird aufgerufen, falls die Konstruktion des Objekts fehlschlägt. Direkt aufrufen kannst du den delete -Operator nicht, du musst ihn in Destruktion und Speicherfreigabe aufteilen.

    X customArg;
    MyClass* m = new (customArg) MyClass;
    
    m->~MyClass();
    operator delete(m, customArg);
    

    Aber du kannst das natürlich kapseln:

    template <typename T>
    void delete_object(T* memory, X customParam)
    {
    	memory->~T();
    	operator delete(memory, customParam);
    }
    

    Bei new ist die Kapselung ohne Perfect Forwarding schwierig, falls T beliebige Konstruktorparameter nehmen können soll.



  • Ok, ich glaub ich bin dahinter gestiegen. new ist ja nicht nur ein operator sondern auch ein keyword.

    Von daher ist es scheinbar nur mit pumuckls variante möglich (placement new) den Konstruktor nach dem Aufruf der Funktion new aufzurufen. Inside the C++ Object Model | ISBN: 0201834545 scheint dass auf Seite 215 zu bestätigen.

    Außerdem hab ich auch eine Seite gefunden, die diese Theroie verfestigt.

    Danke an alle für die Infos

    Grüße
    Tobi



  • Nexus schrieb:

    Benutzerdefinierte new - und delete -Operatoren:

    void* operator new(std::size_t bytes, X customParam);
    void  operator delete(void* memory, X customParam);
    

    Der delete -Operator wird aufgerufen, falls die Konstruktion des Objekts fehlschlägt. Direkt aufrufen kannst du den delete -Operator nicht, du musst ihn in Destruktion und Speicherfreigabe aufteilen.

    X customArg;
    MyClass* m = new (customArg) MyClass;
    
    m->~MyClass();
    operator delete(m, customArg);
    

    Aber du kannst das natürlich kapseln:

    template <typename T>
    void delete_object(T* memory, X customParam)
    {
    	memory->~T();
    	operator delete(memory, customParam);
    }
    

    Bei new ist die Kapselung ohne Perfect Forwarding schwierig, falls T beliebige Konstruktorparameter nehmen können soll.

    Danke Nexus,

    wenn ich dich richtig verstehe festigt auch dass meine Theorie aus dem lezten Post von mir.

    Grüße
    Tobi



  • Tobias Gerg schrieb:

    Dieser Aufruf verheiratet ja auch beides irgendwie. Und bisher dachte ich immer dass die operator syntax nur syntaktischer Zucker ist und der Funktionsaufruf equivalent ist... 😕

    Man muss zwischen zwei Dingen unterscheiden: einmal dem Operator [c]new[/c], was im Grunde das Token/reservierte Schlüsselwort im Quelltext samt seiner Semantik ist. Zum Anderen die Funktion operator new , was eben die Funktion ist, die der Compiler aufruft, wenn er den Operator im Quelltext findet. Ist im Grunde das gleiche wie der Unterschied zwischen dem Operator + , der im Quelltext steht (z.B. im Ausdruck "a+b"), und der Funktion operator+ , die aufgerufen wird, wennd er Compiler den Operator liest.
    Der Unterschied zwischen "new" und "+" ist der, dass der Ausdruck "a+b" einfach übersetzt wird in "operator+(a,b)", also einen Funktoinsaufruf darstellt.
    der Ausdruck "new T(args)" bzw. "new(newargs) T(args)" hingegen sorgt dafür, dass einmal der passende operator new(sizeof(T)) , bzw. operator new(sizeof(T), newargs) aufgerufen wird und dann danach der Konstruktor von T auf dem Speicherbereich ausgeführt wird, den der operator new zurückgegeben hat.

    Der Compiler macht also quasi folgendes daraus:

    //Bsp1: Aufruf "T* pt = new T(25);"
    T* pTemp = (T*)operator new(sizeof(T)); //oder T::operator new, was grade passt - besorgt Speicher
    pTemp->T(25); //Expliziter Ctor-Aufruf ist kein gültiges C++, der Compiler darf das natürlich. Soll Konstruktion an der Stelle im Speicher darstellen
    T* pt = pTemp;
    
    //Bsp2: Aufruf "pt = new(pt) T(25);"
    T* pTemp = (T*)operator new(sizeof(T), pt); //new(size_t, void*) macht nichts! Speicher ist ja schon besorgt
    pTemp->T(25); //Ctor-Aufruf
    pt = pTemp;
    

    Beispiel zwei soll verdeutlichen, dass dieses Placement-new gleichbedeutend mit dem expliziten Ctor-Aufruf ist, weil der zugehörige ::operator new nichts tut (es sei denn er ist überladen)

    Zusammengefasst: normale Operatoren übersetzt der Compiler mit Aufruf der operator XY -Funktion.
    Den Operator new übersetzt der Compiler durch den Aufruf von operator new plus Konstruktion des Objektes.
    Den Operator delete übersetzt der Compiler durch den Aufruf des Destruktors plus Aufruf von operator delete



  • pumuckl schrieb:

    ...

    Hallo pumuckl,

    danke für die ausführlichen Erklärungen. Damit sehe ich das von mir recherchierte als verifiziert an...

    Grüße
    Tobi


Anmelden zum Antworten