2014-03-19 76 views
13

C++ hat eine Option, um einen Nullzeiger zurückzugeben, anstatt eine Bad_alloc Ausnahme zu werfen, wenn eine Zuweisung fehlgeschlagen ist.Wie std :: make_shared und new (std :: nothrow) kombiniert werden

Foo * pf = new(std::nothrow) Foo(1, 2, 3); 

(Ja, ich verstehe dies verhindert, dass nur die neue von einer bad_alloc werfen, es nicht zu werfen eine Ausnahme Foo Konstruktor verhindern.)

Wenn Sie einen freigegebenen Zeiger statt eines verwenden möchten roher Zeiger, sollte man generell make_shared verwenden, da es um die Zuweisung des Kontrollblocks schlau wird.

make_shared kapselt das neue ein, was es unmöglich macht (?), Die Nothrow-Version zu wählen. Es scheint also, du musst make_shared abbrechen und explizit new aufrufen.

std::shared_ptr<Foo> pf(new(std::nothrow) Foo(1, 2, 3)); 

Dadurch entfällt die Optimierung des Steuerblockes mit der Foo Zuweisung und die Steuerblockzuweisung könnte unabhängig von der Foo Zuordnung nicht, aber ich will nicht auf das konzentrieren. Nehmen wir an, der Steuerblock ist klein, so dass seine Zuweisung in der Praxis niemals fehlschlägt. Es ist das Versäumnis, Platz für den Foo zuzuweisen, der mich betrifft.

Gibt es eine Möglichkeit, den Vorteil einer einzigen Zuweisung von make_shared zu erhalten, während die Fähigkeit erhalten bleibt, einfach einen null-Zeiger anstelle einer bad_alloc-Ausnahme zu erhalten, wenn Speicherplatz für den Foo reserviert wird?

+1

Sie müssen wahrscheinlich eine Kopie von 'make_shared' Code machen und es dann nach Bedarf ändern. –

Antwort

6

Es sieht aus wie allocate_shared, in einem Zuordner, der die nothrow neue verwendet, sollte den Trick für Sie tun.

+1

Hinweis: [allocated_shared] (http://en.cppreference.com/w/cpp/memory/shared_ptr/allocate_shared) –

+0

Abgestimmt, da dies IMHO die Zuordneranforderungen brechen würde. (§17.6.3.5 Tabelle 28) Diese Lösung wird auf jeden Fall schrecklich schiefgehen, wenn das System nicht genügend Speicher hat. 'allocate_shared()' von MSVC12 überprüft zum Beispiel nicht den Zeiger, der von 'allocate()' zurückgegeben wird, und würde den Steuerblock gerne mit '(void *) 0' konstruieren. Der erste Versuch, diesen Zeiger zu dereferenzieren, wird wahrscheinlich fehlschlagen. (glücklicherweise geschieht dies auf MSVC12 bereits in 'allocate_shared()'). –

+0

@ Matthäus Brandl Ich habe nichts in dieser Tabelle (C++ 11 Draft Standard) gesehen, das dazu führen würde, dass dies die Allokator-Anforderungen durchbricht, könnten Sie ein bisschen mehr ausarbeiten? –

1

haben nur eine benutzerdefinierte nake_foo und die Ausnahme abfangen:

#include <memory> 

struct Foo { 
    Foo(int, int, int) { throw std::bad_alloc(); } 
}; 

std::shared_ptr<Foo> make_foo(int a, int b, int c) { 
    try { return std::make_shared<Foo>(a, b, c); } 
    catch (const std::bad_alloc&) { return std::shared_ptr<Foo>(); } 
} 
Verwandte Themen