2010-08-13 3 views
19

Einige meiner Code verwendet immer noch malloc anstelle von new. Der Grund ist, weil ich Angst habe, new zu benutzen, weil es Ausnahme wirft, anstatt NULL zurückzugeben, die ich leicht überprüfen kann. Jeden Anruf auf new in einem try{}catch(){} zu wickeln sieht auch nicht so gut aus. Bei Verwendung von malloc kann ich einfach if (!new_mem) { /* handle error */ } tun.Ist es möglich, einen C++ - Smartpointer zusammen mit Cs malloc zu verwenden?

Daher habe ich eine Frage. Kann ich Smartpointer zusammen mit malloc verwenden?

Etwas wie:

SmartPointer<Type> smarty = malloc(sizeof(Type)); 

Etwas Ähnliches.

Ist das möglich?

Danke, Boda Cydo.

+2

Wenn Sie möchten, dass neue jetzt eine Ausnahme auslöst und nur NULL zurückgibt, können Sie Folgendes verwenden: Geben Sie * ein bla = new (std :: nothrow) Type() ;. Ich denke, es ist besser, std :: nothrow als malloc zu verwenden, da später der Konstruktor nicht aufgerufen wird. –

+1

Was werden Sie im Fehlerbehandlungscode tun, um zu kompensieren, dass kein Speicher verfügbar ist? Normalerweise ist der Test, wenn die Zuteilung funktioniert, dann funktionieren. Wenn es fehlgeschlagen ist, beenden Sie mit einem Fehlercode (der eine kompilierte Art ist, die Kontrolle über den Stack zurückgibt). –

Antwort

31

Wenn Sie shared_ptr oder unique_ptr verwenden, können Sie eine benutzerdefinierte deleter angeben. Zum Beispiel

struct free_delete 
{ 
    void operator()(void* x) { free(x); } 
}; 

Dies kann mit shared_ptr wie so verwendet werden:

std::shared_ptr<int> sp((int*)malloc(sizeof(int)), free_delete()); 

Wenn Sie unique_ptr verwenden, ist der deleter ein Teil der unique_ptr ‚s Art, so der deleter muss sein angegeben als Template-Argument:

std::unique_ptr<int, free_delete> up((int*)malloc(sizeof(int))); 

es ist jedoch besser Ausnahmen richtig zu verwenden, anstatt sie zu vermeiden, wenn das Schreiben C++, insbesondere mit r Beachten Sie Zuordnungsfehler. In den meisten Fällen können Sie nicht erfolgreich von einem Zuweisungsfehler in der Funktion wiederherstellen, die versucht, die Zuweisung durchzuführen. Daher können Ausnahmen dazu beitragen, den Fehler zu behandeln, wo Sie ihn tatsächlich verarbeiten können.

+0

Sie können auch 'free' direkt übergeben:' auto myPointer = std :: unique_ptr (..., frei) ' –

+2

@PatrickChilton Beachten Sie, dass wenn Sie dies tun, Ihre' unique_ptr' ist doppelt so groß. –

1

Es hängt davon ab, was der SmartPointer zur Zerstörung tut. Wenn Sie free als Deallocator angeben können, könnte das funktionieren. Mit boost :: shared_ptr können Sie beispielsweise einen Deleter angeben.

Ich habe nicht genug Aufmerksamkeit auf Ihren Grund für das wollen. Ich stimme den anderen Antworten zu, dass die Verwendung des Notfalls new eine viel bessere Idee ist.

1

Es ist möglich, malloc mit intelligenten Zeigern zu verwenden (Sie müssen den Rückgabewert jedoch an den Ziel-Zeigertyp übergeben und einen benutzerdefinierten Deallocator bereitstellen). Aber bessere Option ist, nothrow Version von new Operator zu verwenden.

http://www.cplusplus.com/reference/std/new/nothrow/

9

Sie nothrow Stichwort mit dem neuen Betreiber verwenden, die eher NULL zurück, die eine Ausnahme werfen. Details siehe unten stehenden Link: http://www.cplusplus.com/reference/std/new/nothrow/

+1

Nutzt man 'Nothrow'? (Weil ich selbst nicht persönlich gesehen habe, dass ich selbst in der realen Praxis nichts mache.) – bodacydo

+7

Dies ist die gebräuchlichste Art, 'new' zu verwenden, wenn Sie nicht möchten, dass eine Ausnahme ausgelöst wird. Aber nein, es ist üblicher, einfach "neu" zu verwenden und * mit der Ausnahmebehandlung zu arbeiten. Wenn die Zuweisung fehlschlägt, können Sie normalerweise nicht viel dagegen tun. Eine Ausnahme weiterzugeben ist eine ziemlich saubere Methode, um ordnungsgemäß zu beenden. – jalf

1

Welcher Code ist in /* handle error */? Gibt es irgendetwas, was Sie tatsächlich mit einem Fehler wegen zu wenig Speicher machen können? Ich lasse die Anwendung einfach mit einem Call-Stack (Core-Dump) beenden, damit ich eine Idee an mindestens einen möglichen Ort habe, der Probleme verursachen könnte.Die Verwendung von malloc, um Speicher für C++ - Klassen und -Objekte zuzuweisen, ist keine gute Idee, da nicht sichergestellt wird, dass die Konstruktoren aufgerufen werden, was möglicherweise zu nicht initialisierten Klassen führt, die sogar abstürzen können, wenn sie virtuelle Methoden verwenden.

Verwenden Sie einfach new und delete und machen Sie sich keine Sorgen über das Abfangen der Ausnahme, nachdem alle nicht genügend Arbeitsspeicher ist ein Ausnahmefall und sollte nicht in normalen Läufen der Anwendung passieren.

+0

Es gibt einige Situationen, in denen Sie den Fehler behandeln können. Zum Beispiel können speicherbereite numerische Berechnungen (z. B. Simulationen) auf schwachen Maschinen leicht aus dem Speicher geraten, aber in diesem Fall können Sie sofort anhalten und einen Fehler anzeigen, anstatt abzustürzen. – Yury

1

Verwenden Sie nothrow.

nothrow Konstante

Dieser konstante Wert als für Operator Argument verwendet wird, neue und Operator new [], um anzuzeigen, dass diese Funktionen sind keine Ausnahme auf Ausfall werfen, aber das Rück ein Nullzeiger stattdessen.

char* p = new (nothrow) char [1048576]; 
if (p==NULL) cout << "Failed!\n"; 
else { 
    cout << "Success!\n"; 
    delete[] p; 
} 
3

Die beste Lösung ist new (std::nothrow) Type zu verwenden. Dies wird genau wie new Type funktionieren, aber wird Null geben, anstatt zu werfen, wenn es fehlschlägt. Dies wird viel einfacher als zu versuchen, malloc Verhalten wie new zu machen.

Wenn Sie wirklich malloc verwenden müssen, dann denken Sie daran, das Objekt korrekt zu konstruieren und zu zerstören:

void* memory = malloc(sizeof(Type)); 
Type* object = new (memory) Type; 
object->~Type(); 
free(object); // or free(memory) 

Sie diese mit ein paar intelligente Zeiger verwenden kann eine benutzerdefinierte deleter, indem sie:

void malloc_deleter(Type* object) 
{ 
    object->~Type(); 
    free(object); 
} 

if (void* memory = malloc(sizeof(Type))) 
{ 
    Type* object = new (memory) Type; 
    std::shared_ptr<Type> ptr(object, malloc_deleter); 
    DoStuff(ptr); 
} 

Aber das wäre viel einfacher, wenn man nicht werfen neue:

if (Type* object = new (std::nothrow) Type) 
{   
    std::shared_ptr<Type> ptr(object); 
    DoStuff(ptr); 
} 
+0

Die Verwendung von malloc hat den zusätzlichen Vorteil, dass Sie realloc verwenden können: http://stackoverflow.com/a/33706568/1858225 –

1

Ich habe eine Frage.

Was passiert, wenn "Typ" ein Typ ist, dessen Konstruktor werfen kann? In diesem Fall muss man noch Ausnahmen in einem try/catch-Block behandeln.

Ist es also eine gute Idee, den ausnahmebasierten Ansatz aufzugeben?

Ich würde sagen, dass man das Abstract Factory/Factory Method Entwurfsmuster verwenden kann und alle "neuen" in relativ weniger Dateien/Namespaces/Klassen hat, als dass diese überall verstreut sind. Dies kann auch dazu beitragen, die Verwendung von try/catch-Block auf einen relativ geringeren Code zu beschränken.

Verwandte Themen