Hat irgendjemand hier jemals die "Platzierung neu" von C++ verwendet? Wenn ja, wofür? Für mich sieht es so aus, als ob es nur auf memory-mapped Hardware nützlich wäre.
Antworten
Zu viele Anzeigen?Die Platzierung von new ermöglicht es Ihnen, ein Objekt im bereits zugewiesenen Speicher zu konstruieren.
Dies kann aus Optimierungsgründen sinnvoll sein, wenn Sie mehrere Instanzen eines Objekts erstellen müssen und es schneller ist, nicht jedes Mal, wenn Sie eine neue Instanz benötigen, erneut Speicher zuzuweisen. Stattdessen kann es effizienter sein, eine einzige Zuweisung für einen Speicherbereich vorzunehmen, der mehrere Objekte aufnehmen kann, auch wenn Sie nicht den gesamten Speicher auf einmal verwenden möchten.
DevX gibt eine gutes Beispiel :
Standard-C++ unterstützt auch die Platzierung new-Operator, der ein Objekt auf einem zuvor zugewiesenen Puffer konstruiert. Dieser ist nützlich beim Aufbau eines Speicherpools, eines Garbage Collectors oder einfach, wenn Leistung und Ausnahmesicherheit im Vordergrund stehen (es besteht keine Gefahr von Allokationsfehler, da der Speicher bereits zugewiesen wurde, und Konstruieren eines Objekts auf einem bereits zugewiesenen Puffer benötigt weniger Zeit):
char *buf = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi"); // placement new
string *q = new string("hi"); // ordinary heap allocation
Sie können auch sicher sein, dass an einem bestimmten Teil des kritischen Codes (z. B. im Code, der von einem Herzschrittmacher ausgeführt wird) kein Zuweisungsfehler auftreten kann. In diesem Fall sollten Sie den Speicher früher zuweisen und dann die neue Platzierung innerhalb des kritischen Abschnitts verwenden.
Deallokation in der Platzierung neu
Sie sollten nicht jedes Objekt, das den Speicherpuffer verwendet, deallokieren. Stattdessen sollten Sie nur den ursprünglichen Puffer löschen[]. Sie müssten dann die Destruktoren Ihrer Klassen manuell aufrufen. Einen guten Vorschlag hierzu finden Sie in Stroustrups FAQ zu: Gibt es eine "Platzierung löschen" ?
Wir verwenden es mit benutzerdefinierten Speicherpools. Nur eine Skizze:
class Pool {
public:
Pool() { /* implementation details irrelevant */ };
virtual ~Pool() { /* ditto */ };
virtual void *allocate(size_t);
virtual void deallocate(void *);
static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};
class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };
// elsewhere...
void *pnew_new(size_t size)
{
return Pool::misc_pool()->allocate(size);
}
void *pnew_new(size_t size, Pool *pool_p)
{
if (!pool_p) {
return Pool::misc_pool()->allocate(size);
}
else {
return pool_p->allocate(size);
}
}
void pnew_delete(void *p)
{
Pool *hp = Pool::find_pool(p);
// note: if p == 0, then Pool::find_pool(p) will return 0.
if (hp) {
hp->deallocate(p);
}
}
// elsewhere...
class Obj {
public:
// misc ctors, dtors, etc.
// just a sampling of new/del operators
void *operator new(size_t s) { return pnew_new(s); }
void *operator new(size_t s, Pool *hp) { return pnew_new(s, hp); }
void operator delete(void *dp) { pnew_delete(dp); }
void operator delete(void *dp, Pool*) { pnew_delete(dp); }
void *operator new[](size_t s) { return pnew_new(s); }
void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
void operator delete[](void *dp) { pnew_delete(dp); }
void operator delete[](void *dp, Pool*) { pnew_delete(dp); }
};
// elsewhere...
ClusterPool *cp = new ClusterPool(arg1, arg2, ...);
Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);
Jetzt können Sie Objekte in einer einzigen Speicherarena zusammenfassen, einen Allokator auswählen, der sehr schnell ist, aber keine Freigabe vornimmt, Speicherzuordnung verwenden und jede andere Semantik, die Sie auferlegen möchten, indem Sie den Pool auswählen und ihn als Argument an den Operator für die Platzierung neuer Objekte übergeben.
Ich habe es bei der Echtzeitprogrammierung eingesetzt. Wir haben typischerweise nicht eine dynamische Zuweisung (oder Freigabe) nach dem Systemstart durchführen wollen, weil es keine Garantie dafür gibt, wie lange das dauern wird.
Was ich tun kann, ist, einen großen Teil des Speichers im Voraus zuzuweisen (groß genug, um eine beliebige Menge von allem zu speichern, was die Klasse benötigen könnte). Wenn ich dann zur Laufzeit herausfinde, wie ich die Dinge konstruieren soll, kann ich die neue Platzierung verwenden, um Objekte genau dort zu konstruieren, wo ich sie haben will. Eine Situation, die ich kenne, in der ich es verwendet habe, war die Erstellung eines heterogenen Ringspeicher .
Es ist sicherlich nichts für schwache Nerven, aber deshalb ist die Syntax dafür auch so krass.
- See previous answers
- Weitere Antworten anzeigen