515 Stimmen

Welche Verwendungszwecke gibt es für "Platzierung neu"?

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.

465voto

Brian R. Bondy Punkte 325712

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" ?

75voto

Don Wakefield Punkte 8445

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.

57voto

MSN Punkte 51308

Sie ist nützlich, wenn Sie die Zuweisung von der Initialisierung trennen wollen. STL verwendet Platzierung neu, um Container-Elemente zu erstellen.

44voto

T.E.D. Punkte 42630

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.

28voto

Ferruccio Punkte 96076

Ich habe es verwendet, um Objekte zu konstruieren, die mit alloca() auf dem Stack zugewiesen wurden.

schamlose Werbung: Ich habe darüber gebloggt ici .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X