2010-12-08 6 views
3

Ich habe eine Klasse A. Einige Bibliotheken, die ich verwende, weisen mir eine bestimmte Speichergröße zu, sizeof A, und gibt einen void-Zeiger darauf zurück.C++: Klasseninstanz im zugewiesenen Speicher ablegen

A* pObj = (A*) some_allocator_im_forced_to_use(sizeof A); 

Nun, wie kann ich eine neue Instanz von A, im Speicher erstellen, wurde gerade zugewiesen?

Ich habe es versucht, mit:

*pObj = A(); 

Aber das hat nicht funktioniert - wurde der destructor direkt nach dem Konstruktor von A.

Antwort

8

Sie Platzierung kann neue genannt:

A* pObj = new (some_allocator_im_forced_to_use(sizeof(A))) A; 

Dies erstellt eine neue A Instanz an der Stelle, die von der Funktion some_allocator_im_forced_to_use zurückgegeben wird. Diese Funktion muss einen void* zurückgeben, der auf ausreichenden Speicher zeigt, der für ein A Objekt auf der fraglichen Implementierung passend ausgerichtet wird.

Es ist wahrscheinlich, dass Sie den Destruktor für dieses Objekt manuell manuell aufrufen müssen, da Sie das übliche delete pObj nicht verwenden können, um es zu zerstören.

pObj->~A(); 
// Call custom allocator's corresponding deallocation function on (void*)pObj 

Um den Speicher korrekt zu zerstören das Objekt und lassen Sie sich anschauen sollten eine shared_ptr mit einem benutzerdefinierten deleter verwenden.

3

Verwenden Platzierung neu:

new (pObj) A; 

Sie müssen auch das Objekt unterschiedlich zerstören, da delete geht davon aus (falsch), dass Sie das Objekt mit einfachen alten new erstellt:

pObj->~A(); 
some_deallocator_im_forced_to_use(pObj); 
0

Wenn Ihr allocator das Modell der std::allocator folgt soll es mehrere Methoden:

  • allocate
  • construct
  • destroy
  • deallocate

Sie ziemlich selbsterklärend sind, was wichtig ist, ist, dass Sie für den Aufruf von ihnen verantwortlich sind:

  • in der richtigen Reihenfolge
  • und keine
vergessen

oder Sie erhalten entweder UB oder ein Leck.

Aber ich bin etwas überrascht, dass nur die Größe von Ihrem Allokator erforderlich ist, normalerweise erfordert es auch die Ausrichtung des Objekts, es sei denn, es verwendet einfach die maximale Ausrichtung auf das Ziel unabhängig von dem Objekt zuzuordnen.

1

Einige Leute haben neue Placierung befürwortet.

Das ist gefährlich, und die bisher zwei Verwendungsbeispiele haben wichtige Details wie die <new> Header, qualifizieren den Anruf wie ::new ... und wie aufräumen weggelassen.

Die sichere Lösung besteht darin, benutzerdefinierte Zuordnungs- und Freigabe-Funktionen für Ihre Klasse oder für eine von Ihrer Klasse abgeleitete Klasse zu definieren. Das folgende Beispiel zeigt Letzteres. Beachten Sie, dass der virtuelle Destruktor nur dazu da ist, die Klassenableitung zu unterstützen. Wenn Sie nicht ableiten, brauchen Sie es nicht.

#include <stddef.h> 
#include <iostream> 

void* some_allocator_im_forced_to_use(size_t size) 
{ 
    std::cout << "Allocated " << size << " bytes." << std::endl; 
    return ::operator new(size); 
} 

void some_deallocator_im_forced_to_use(void* p, size_t size) 
{ 
    std::cout << "Deallocated " << size << " bytes." << std::endl; 
    ::operator delete(p); 
} 

struct A 
{ 
    int x_; 
    A(): x_(42) {} 
    virtual ~A() {} 
}; 

struct CustomAllocedA 
    : A 
{ 
    void* operator new(size_t size) 
    { 
     return some_allocator_im_forced_to_use(size); 
    } 

    void operator delete(void* p, size_t size) 
    { 
     some_deallocator_im_forced_to_use(p, size); 
    } 
}; 

int main() 
{ 
    A* const p = new CustomAllocedA; 

    std::cout << p->x_ << std::endl; 
    delete p; 
} 

Wichtig: obwohl dies „sicher“ in sich selbst, und obwohl dieses Beispiel sicher ist, ruht die Sicherheit für Ihre Code letztlich auf Ihrer benutzerdefinierten einen Zeiger allocator Rückkehr richtig Speicher ausgerichtet.

Beifall & hth.,

+0

1 die neuen Betreiber zu überschreiben ist absolut eine viel bessere Idee als neue Verwendung Platzierung. –

Verwandte Themen