¿Qué usos tiene la “colocación nueva”?

Resuelto Head Geek asked hace 15 años • 25 respuestas

¿Alguien aquí ha utilizado alguna vez la "ubicación nueva" de C++? Si es así, ¿para qué? Me parece que sólo sería útil en hardware mapeado en memoria.

Head Geek avatar Oct 21 '08 23:10 Head Geek
Aceptado

La ubicación nueva le permite construir un objeto en la memoria que ya está asignado.

Es posible que desee hacer esto para optimizar cuando necesite construir varias instancias de un objeto, y es más rápido no reasignar memoria cada vez que necesite una nueva instancia. En cambio, podría ser más eficiente realizar una asignación única para una porción de memoria que puede contener múltiples objetos, aunque no desee usarlos todos a la vez.

DevX da un buen ejemplo :

El C++ estándar también admite la colocación de un nuevo operador, que construye un objeto en un búfer preasignado. Esto es útil cuando se crea un grupo de memoria, un recolector de basura o simplemente cuando el rendimiento y la seguridad de excepciones son primordiales (no hay peligro de que falle la asignación ya que la memoria ya ha sido asignada y construir un objeto en un búfer preasignado lleva menos tiempo). :

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

También es posible que desee asegurarse de que no pueda haber ningún error de asignación en una determinada parte del código crítico (por ejemplo, en el código ejecutado por un marcapasos). En ese caso, querrás asignar memoria antes y luego usar la ubicación nueva dentro de la sección crítica.

Desasignación en colocación nueva

No debe desasignar todos los objetos que utilizan el búfer de memoria. En su lugar, deberías eliminar[] solo el búfer original. Luego tendrías que llamar manualmente a los destructores de tus clases. Para obtener una buena sugerencia al respecto, consulte las preguntas frecuentes de Stroustrup sobre: ​​¿Existe una "eliminación de ubicación" ?

Brian R. Bondy avatar Oct 21 '2008 16:10 Brian R. Bondy

Lo usamos con grupos de memoria personalizados. Sólo un boceto:

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool *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, ...);

Ahora puede agrupar objetos en un único campo de memoria, seleccionar un asignador que sea muy rápido pero que no desasigne, usar mapeo de memoria y cualquier otra semántica que desee imponer eligiendo el grupo y pasándolo como argumento a la ubicación de un objeto. nuevo operador.

Don Wakefield avatar Oct 21 '2008 16:10 Don Wakefield

Es útil si desea separar la asignación de la inicialización. STL utiliza la ubicación nueva para crear elementos contenedores.

MSN avatar Oct 21 '2008 16:10 MSN

Lo he usado en programación en tiempo real. Por lo general, no queremos realizar ninguna asignación (o desasignación) dinámica después de que se inicia el sistema, porque no hay garantía de cuánto tiempo llevará.

Lo que puedo hacer es preasignar una gran cantidad de memoria (lo suficientemente grande como para contener cualquier cantidad de lo que la clase pueda requerir). Luego, una vez que descubro en tiempo de ejecución cómo construir las cosas, puedo usar la ubicación nueva para construir objetos justo donde los quiero. Una situación en la que sé que lo usé fue para ayudar a crear un búfer circular heterogéneo .

Ciertamente no es para los débiles de corazón, pero es por eso que hacen que la sintaxis sea un poco retorcida.

T.E.D. avatar Oct 21 '2008 17:10 T.E.D.