2017-09-28 1 views
0

Kennt jemand eine C++ - Löschprozedur, die sowohl für die neue als auch für die normale neue Installation sicher ist?Löschen für Placement oder Nicht-Placement neu

Object* regular = new Object(); 
delete_procedure(regular); 

void* buf = ::new(sizeof(Object)); 
Object* placement = new(buf) Object(); 
delete_procedure(placement); 

Diese Funktion scheint zu funktionieren, aber ich kann nicht herausfinden, ob es für beiden Instanzen tatsächlich sicher ist (es ist die Standard-Methode Platzierung neu zu löschen).

+0

Wenn Sie sich interessieren: Warum brauche ich das? Ich schreibe einen Garbage Collector für gleichzeitige Datenstrukturen und einige Objekte, die der GC managt, können effektiv über die neue Platzierung für die Effizienz unterschiedlich dimensioniert werden (zB Metadaten gefolgt von c String), einige Objekte sind möglicherweise nicht, und ich möchte mich nicht darauf verlassen auf den Benutzer, um den Unterschied zu verfolgen. – Joe

+2

Eine solche Prozedur kann nicht existieren, da Sie das 'delete' mit dem entsprechenden' new' vergleichen müssen, und außerdem gibt es keinen "placement-delete expression". –

+0

Immer Placement neu verwenden? –

Antwort

3

Ich glaube nicht, dass es eine einheitliche Methode gibt, dies zu tun, ohne einige zusätzliche Flags einzuführen, um Dinge zu markieren. Die C++ - Philosophie lautet: "Sie müssen verfolgen, wie Sie Dinge zugewiesen haben und sicherstellen, dass sie alle ordnungsgemäß zerstört werden", und zwar aus Effizienzgründen. Denken Sie an delete[] gegenüber delete. Es könnte ein vereinheitlichtes Schlüsselwort delete geben, das jeden Speicherblock bereinigt, aber das würde einen Leistungsoverhead verursachen, weil die Kosten für die Ermittlung der Aufzuweisungsroutine anfallen. Oder denken Sie an virtuelle Destruktoren: C++ könnte sagen, dass delete immer eine Art Introspektion durchführt, aber das würde allen Objekttypen einen Overhead hinzufügen, viel davon unnötig.

Die Philosophie von C++ lautet: "Zahlen Sie nicht für das, was Sie nicht verwenden". Wenn Sie also etwas einheitliches erstellen möchten, müssen Sie eine zusätzliche Infrastruktur einrichten, um zu verfolgen, welche Löschroutinen Sie benötigen machen.

+0

Ich wäre überrascht, wenn es eine Plattform gibt, wo Flags notwendig sind, vorausgesetzt, dass der Zuweisungsausdruck fest ist. Beachten Sie, dass dies eine Frage in der Praxis ist und keine Frage eines Sprachanwalts. Wie auch immer, diese Antwort ist ein Kommentar, der deinen Glauben und einige Ratschläge darüber ausdrückt, worüber du nachdenken solltest, keine Antwort, also als solche gekennzeichnet. –

1

Nein, wegen Arrays und Details. Sicher, weil diese Probleme in Ihrer Codebasis wahrscheinlich keine Rolle spielen.

Alle Löschungen sind entweder typspezifische Löschungen oder:

Das Verhalten der Standardbibliothek Implementierung dieser Funktion ist nicht definiert, es sei denn ptr ein Nullzeiger oder ein Zeiger ist bereits aus der Standardbibliothek Implementierung erhalten von operator new (size_t) oder operator new (size_t, std :: nothrow_t).

von http://en.cppreference.com/w/cpp/memory/new/operator_delete

Dies bedeutet Speicher durch new[](size_t) zu delete(void*) zugeordnet vorbei ist UB und new[](size_t) zu delete[](void*) UB ist.


Zweitens sind Benutzer frei, neue/löschen auf einer globalen oder pro Klasse zu ersetzen.


Drittens:

void delete_procedure(Object* obj){ 
    obj->~Object(); 
    ::operator delete((void*)obj); 
} 

Sie werfen wollen werden Zeiger dort für ungültig zu erklären und verwenden Betreiber löschen.


Forth, der Zeiger auf delete_procedure geben muss der Zeiger durch new T oder ::new(::new(sizeof(T))) T erzeugt werden kann; Es kann kein Zeiger auf ein Unterobjekt abgeleitet sein, da sein Wert void* abweichen kann.

Wenn T* pt dynamisch gießbar ist, wird dynamic_cast<void*>(pt) das void* rekonstruieren. Das ist also weniger eine Barriere als es scheint. Denken Sie daran, die Besetzung zu tun, bevor Sie das Objekt zerstören!

void delete_procedure_dynamic(Object* obj){ 
    void* ptr=dynamic_cast<void*>(obj); 
    obj->~Object(); 
    ::operator delete(ptr); 
} 

und SFINAE/Tag-Dispatching verwenden, um zwischen den dynamischen und nicht dynamischen Versionen zu versenden.


Fünftens müssen hohe Ausrichtungstypen Arbeit verarbeiten. Sie verwenden verschiedene neue und löschen. Ich bin unsicher, wie dynamische Casting und überabgerichtete abgeleitete Typen interagieren würden, aber wahrscheinlich müssen Sie sich nicht kümmern.


Aber new T Anrufe ::new(size_t)`` then constructs an object there. Operator löschen (void *) must be fed memory produced by :: neu (size_t) . Destroying an object creates by neue T is legal via. ~ T() `. Ich sehe also nichts grundsätzlich gebrochen.

In der Praxis, was ich tun könnte, überschreiben "normal" neu, um das gleiche Muster wie Ihre zusätzlichen Speicher neu zu folgen (und den Block über new(size_t) zuweisen), um die Dinge einfach zu halten. Sie befinden sich in einem arkanen Territorium, warum machen Sie die Dinge nicht einheitlich?

+0

Könnte marginal noch besser sein, wenn man 'dynamic_cast ' erwähnt, um das komplette Objekt zu erhalten. Oh, und Ausnahmesicherheit. Ich denke der OP hat Pseudocode gepostet, ich kann nicht sehen, wie das kompilieren könnte. –

Verwandte Themen