2013-03-08 3 views
9

Ich habe ein C++ - Programm, in dem der Operator new überlastet ist. Das Problem ist, dass , wenn meine Zuweisung in der new-Operator fehlschlägt, ich immer noch den Konstruktor aufrufen. Ich weiß, dass ich das vermeiden kann, indem ich std::bad_alloc werfe, aber ich will das nicht tun.Wie wird `new (std :: nothrow)` implementiert?

Wie kann ich in meinem überladenen new-Operator fehlschlagen und meinen Konstruktor immer noch nicht aufrufen? Im Wesentlichen möchte ich etwas wie new (std::nothrow) implementieren.

Hier ist ein Beispiel zur Veranschaulichung, was ich meine. Beachten Sie, dass das getestete System keinen Speicherschutz hat. So NULL Zugriff tut nichts

Beispiel 1: Überladene neue Betreiber

#include <stdio.h> 
#include <stdlib.h> 
#include <memory> 

class Test { 

public: 

    Test(void) { 
     printf("Test constructor\n"); 
    } 

    void print(void) { 
     printf("this: %p\n", this); 
    } 

    void* operator new(size_t size, unsigned int extra) { 

     void* ptr = malloc(size + extra); 
     ptr = NULL; // For testing purposes 
     if (ptr == NULL) { 
      // ? 
     } 
     return ptr; 
    } 
}; 

int main(void) { 

    Test* t = new (1) Test;    
    t->print(); 
    printf("t: %p\n", t); 

    return 0; 
} 

Die ouput hierfür ist:

$ ./a.out 
Test constructor 
this: 00000000 
t: 00000000 

Klar, dass die constrcutor aufgerufen wird, wenn die new fehlgeschlagen.

Beispiel 2: Sehr große Klassendeklaration mit neuer (std :: nothrow)

#include <stdio.h> 
#include <stdlib.h> 
#include <memory> 

class Test { 

    int x0[0x0fffffff]; 
    int x1[0x0fffffff]; 
    int x2[0x0fffffff]; 
    int x3[0x0fffffff]; 
    int x4[0x0fffffff]; 
    int x5[0x0fffffff]; 
    int x6[0x0fffffff]; 
    int x7[0x0fffffff]; 
    int x8[0x0fffffff]; 
    int x9[0x0fffffff]; 
    int xa[0x0fffffff]; 
    int xb[0x0fffffff]; 
    int xc[0x0fffffff]; 
    int xd[0x0fffffff]; 
    int xe[0x0fffffff]; 
    int xf[0x0fffffff]; 

public: 

    Test(void) { 
     printf("Test constructor\n"); 
    } 

    void print(void) { 
     printf("this: %p\n", this); 
    } 
}; 

int main(void) { 

    Test* t = new (std::nothrow) Test;  
    t->print(); 
    printf("t: %p\n", t); 

    return 0; 
} 

Die ouput hierfür ist:

this: 00000000 
t: 00000000  

Klar, dass die constrcutor ist nicht genannt zu werden wenn die new fehlgeschlagen.

Also wie implementiere ich new (std::nothrow) Art der Funktionalität in meinem überladenen new Operator?

Antwort

9

Ob der Compiler überprüft für einen Null-Zeiger nach operator new oder nicht nennen, bevor die destructor Aufruf, hängt davon ab, ob die Zuordnungsfunktion eine nicht werfen Ausnahme Spezifikation hat oder nicht. Wenn nicht, nimmt der Compiler an, dass operator new wird werfen, wenn kein Speicher verfügbar ist. Andernfalls wird angenommen, dass operator new einen Nullzeiger zurückgibt. In Ihrem Fall sollten Sie Ihre operator new sein:

void* operator new(size_t size, unsigned int extra) throw() 
{ 
    //... 
} 

oder wenn Sie auf C++ 11-Unterstützung zählen:

void* operator new(size_t size, unsigned int extra) noexcept 
{ 
} 
+0

Vielen Dank, hätte ich nie die Antwort erraten. Nur eine Frage, was immer du gesagt hast, ist es überall im C++ 2003 Standard dokumentiert? – tinkerbeast

+1

§5.3.4/13: "Wenn die Zuweisungsfunktion null zurückgibt, darf die Initialisierung nicht erfolgen, die Freigabefunktion darf nicht aufgerufen werden, und der Wert des neuen Ausdrucks muss null sein." –

+1

Tatsächlich wird das Verhalten in C++ 11 und C++ 03 in '[basic.stc.dynamic.allocation]/3' angegeben.Für C++ 11 lautet der Wortlaut wie folgt: "Wenn eine mit einer nicht auswerfenden Ausnahmebestimmung deklarierte Zuweisungsfunktion keinen Speicher zuweist, gibt sie einen Nullzeiger zurück. Jede andere Zuweisungsfunktion, die keinen Speicher zuweist, muss nur einen Fehler anzeigen eine Ausnahme eines Typs auslösen, der einem Handler vom Typ std :: bad_alloc entspricht. " Der Wortlaut von C++ 03 ist sehr ähnlich. – Mankarse

Verwandte Themen