2009-11-10 11 views
5

Ich portiere eine mittelgroße Anwendung von C nach C++. Ausnahmen werden nicht behandelt, und das sollte sich nicht ändern.Vermeiden Sie std :: bad_alloc. new sollte einen Nullzeiger zurückgeben

Mein (falsches!) Verständnis von C++ war (bis ich es gestern auf die harte Tour gelernt habe), dass der (default) new-Operator einen NULL-Zeiger im Falle eines Allokationsproblems zurückgibt. Dies galt jedoch nur bis 1993 (oder so). Heutzutage wird eine std :: bad_alloc-Ausnahme ausgelöst.

Ist es möglich, zu dem alten Verhalten zurückzukehren, ohne alles neu zu schreiben, um bei jedem einzelnen Anruf std :: nothrow zu verwenden?

+2

Das könnte Sie auch interessieren: http://stackoverflow.com/questions/550451/will-new-return-null-in-any-case – Naveen

+6

Bite the bullet. Fixe deinen Code, um std :: nothrow zu verwenden. awk und ein paar reguläre Ausdrücke werden dir 90% des Weges dorthin bringen. –

+0

+1 für wirklich aktuelle Sache für viele Menschen, obwohl ich dagegen bin, solche Dinge zu tun (und ich antwortete unten warum). –

Antwort

11

Sie Betreiber neu überlasten könnten:

#include <vector> 

void *operator new(size_t pAmount) // throw (std::bad_alloc) 
{ 
    // just forward to the default no-throwing version. 
    return ::operator new(pAmount, std::nothrow); 
} 

int main(void) 
{ 
    typedef std::vector<int> container; 

    container v; 
    v.reserve(v.max_size()); // should fail 
} 
+1

@GMan: In dem Beispiel ist der Fehler nicht klar: soll es die Nachteile von nothrow zeigen? – stefaanv

+2

Dies wird wahrscheinlich tödlich scheitern.Standardcontainer arbeiten mit dem Speicher, der den Zuordner verwendet (standardmäßig Standardzuordner), und mindestens einer von ihnen erwartet, dass die Ausnahme ausgelöst wird, wenn kein Speicher vorhanden ist, und nicht nach dem Rückgabewert NULL sucht. Auch dies löst nicht das Problem des Betreibers neu für eine Klasse überlastet. Dies ist jedoch unwahrscheinlich Problem unter Berücksichtigung der Code ist portiert von C. –

+0

Ja, es sollte "erfolgreich" ohne Ausnahmen ausgeführt werden. Und behalte Adam im Sinn; Sie arbeiten im Prinzip daran, wie "Operator neu" bei einem Fehler funktioniert, und einige Leute verlassen sich darauf. Sie sind jedoch keiner von ihnen. :) – GManNickG

0

Ihr Compiler wahrscheinlich ein Kommandozeilen-Schalter hat, dieses Verhalten zu aktivieren/deaktivieren.

+2

eine viel hilfreichere Antwort wäre gewesen, tatsächlich den Befehlszeilenschalter zu schreiben, der angeblich existiert, zumindest für gcc und VC++. –

3

Fügen Sie die Kopfzeile hinzu <new>. Es enthält ein „no-Wurf“ -Version neuer Sie wie folgt verwenden können:

#include <new> 

int main() { 
    int* p = new(std::nothrow) int; 
    if (p) { 
     delete p; 
    } 
} 

Edit: ich zugeben, dass ich den letzten Satz der Frage verfehlt. Aber um ehrlich zu sein, denke ich, dass es auch keine gute Idee ist, "plain new" auf vor-Standard-Verhalten zu optimieren. Ich würde in eine Art automatische Suche schauen & ersetzen, um jedes new in new(std::nothrow) zu drehen.

+2

Sie haben den fettgedruckten Absatz verpasst. –

+0

Ja, scheint so zu sein. Ich habe die 2. Hälfte verpasst. – sellibitze

1

Entschuldigung, aber meiner Meinung nach sollten Sie dies NICHT tun und zu altem neuen Verhalten zurückkehren. Das liegt daran, dass Sie Ausnahmen sowieso nicht vermeiden können.

WARUM?

Berücksichtigen Sie über neue Aufruf, die Klasse mit Konstruktor zuweisen sollte einige Initialisierung Code aufrufen, die alle temporären, die dynamisch ist konstruieren muss. Ach, du wirst eine Ausnahme haben. Egal, ob Sie std :: nothrow verwenden. Dies ist nur ein Szenario unter einer Anzahl von ihnen.

In Scott Meyers Buch Effective C++ wurde soweit ich mich erinnere ausführlich besprochen. Aber ich bin mir nicht sicher, ob alle Fälle überprüft werden (aber ich schlage genug davon vor).

+0

Ich benutze den Konstruktor nur für Zuordnungen. Für alles weitere verwende ich eine "bool Init()" Methode. – dmeister

+0

Dinge ändern sich immer. Es könnte passieren, auch nachdem Sie die Unterstützung dieses Codes fallen lassen und auf die andere Seite des Globus ziehen. Ich habe gerade bemerkt, dass ich eine Anzahl von Fällen gesehen habe, in denen Leute zu viel Vertrauen in std :: nothrow getan haben. Aber es ist keine Magie ;-). –

1

Probieren Sie es aus:

1.Define eine Funktion, die Sie aus dem Speicher Zustand aufrufen möchten.

2.Pass diese Funktion zu set_ neue _handler Funktion, so dass wenn neue fehlschlägt diese Funktion aufgerufen wird.

+0

Ich war mir dessen nicht bewusst, aber der Standardentwurf besagt, dass der "neue_Handler" a) mehr Speicher verfügbar machen und zurückgeben kann, b) throw "std :: bad_alloc" oder abgeleitete Ausnahme, c) call abort() oder exit(). Was Sie nicht tun können, ist eine neue Rückkehr 0 anstatt zu werfen. – UncleBens

Verwandte Themen