Colocación de un nuevo operador en C++

Placement new es un nuevo operador de variación en C++. El nuevo operador normal hace dos cosas: (1) Asigna memoria (2) Construye un objeto en la memoria asignada. 
La colocación nueva nos permite separar las dos cosas anteriores. En la ubicación nueva, podemos pasar una memoria preasignada y construir un objeto en la memoria pasada. 
 

nueva vs ubicación nueva

  • Normal new asigna memoria en montón y construye objetos allí mientras que usando la ubicación new , la construcción de objetos se puede hacer en una dirección conocida .
  • Con normal new, no se sabe a qué dirección o ubicación de memoria apunta, mientras que la dirección o ubicación de memoria a la que apunta se conoce al usar la ubicación new.
  • La desasignación se realiza mediante la operación de eliminación cuando la asignación se realiza por nuevo pero no hay eliminación de ubicación, pero si es necesario, se puede escribir con la ayuda de destructor .

Sintaxis: 
 

new (address) (type) initializer
As we can see, we can specify an address
where we want a new object of given type 
to be constructed.

¿Cuándo preferir usar la ubicación nueva?

Como permite construir un objeto en la memoria que ya está asignada, es necesario para las optimizaciones, ya que es más rápido no reasignar todo el tiempo. Puede haber casos en los que sea necesario reconstruir un objeto varias veces, por lo que la colocación de un nuevo operador podría ser más eficiente en estos casos. 
 

CPP

// C++ program to illustrate the placement new operator
#include<iostream>
using namespace std;
  
int main()
{
    // buffer on stack
    unsigned char buf[sizeof(int)*2] ;
  
    // placement new in buf
    int *pInt = new (buf) int(3);
  
    int *qInt = new (buf + sizeof (int)) int(5);
    int *pBuf = (int*)(buf+0) ;
    int *qBuf = (int*) (buf + sizeof(int));
    cout << "Buff Addr             Int Addr" << endl;
    cout << pBuf <<"             " << pInt << endl;
    cout << qBuf <<"             " << qInt << endl;
    cout << "------------------------------" << endl;
    cout << "1st Int             2nd Int" << endl;
    cout << *pBuf << "                         "
         << *qBuf << endl;
  
    return 0;
}

Producción: 
 

Buff Addr              Int Addr
0x69fed8               0x69fed8
0x69fedc               0x69fedc
------------------------------
1st Int                2nd Int
3                      5

El siguiente diagrama muestra pictóricamente lo que realmente está sucediendo en el programa C++ anterior.
 

Placement new operator in C++ 1

A continuación se muestra otra implementación simple en C++ para ilustrar el uso de la ubicación nueva en C++:
 

CPP

// C++ program to illustrate the placement new operator
#include<iostream>
using namespace std;
int main()
{
    // initial value of X
    int X = 10;
  
    cout << "Before placement new :" << endl;
    cout << "X : " << X << endl;
    cout << "&X : " << &X << endl;
  
    // Placement new changes the value of X to 100
    int *mem = new (&X) int(100);
  
    cout << "\nAfter placement new :" << endl;
    cout << "X : " << X << endl;
    cout << "mem : " << mem << endl;
    cout << "&X : " << &X << endl;
  
    return 0;
}

Producción: 
 

Before placement new :
X : 10
&X : 0x69fee8

After placement new :
X : 100
mem : 0x69fee8
&X : 0x69fee8

Explicación: Aquí, está claro que se asigna un nuevo valor de x en la dirección de x con la ayuda del nuevo operador de ubicación. Esto queda claro por el hecho de que el valor de &X y mem es igual. 
El siguiente diagrama muestra pictóricamente lo que realmente está sucediendo en el programa C++ anterior.
 

Placement new operator in C++ 2

¿Cómo eliminar la memoria asignada por ubicación nueva?

El operador eliminar solo puede eliminar el almacenamiento creado en el montón, por lo que cuando se usa la ubicación nueva, el operador eliminar no se puede usar para eliminar el almacenamiento. En el caso de la asignación de memoria utilizando el operador de ubicación nueva, dado que se crea en la pila , el compilador sabe cuándo eliminarlo y manejará la desasignación de la memoria automáticamente. Si es necesario, se puede escribir con la ayuda de destructor como se muestra a continuación.
 

CPP

// C++ program to illustrate using destructor for
// deleting memory allocated by placement new
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
  
class Complex
{
private:
    double re_, im_;
public:
    // Constructor
    Complex(double re = 0, double im = 0): re_(re), im_(im)
    {
        cout << "Constructor : (" << re_
             << ", " << im_ << ")" << endl;
    }
  
    // Destructor
    ~Complex()
    {
        cout << "Destructor : (" << re_ << ", "
             << im_ << ")" << endl;
    }
  
    double normal()
    {
        return sqrt(re_*re_ + im_*im_);
    }
  
    void print()
    {
        cout << "|" << re_ <<" +j" << im_
             << " | = " << normal() << endl;
    }
};
  
// Driver code
int main()
{
    // buffer on stack
    unsigned char buf[100];
  
    Complex* pc = new Complex(4.2, 5.3);
    Complex* pd = new Complex[2];
  
    // using placement new
    Complex *pe = new (buf) Complex(2.6, 3.9);
  
    // use objects
    pc -> print();
    pd[0].print();
    pd[1].print();
    pe->print();
  
    // Release objects
    // calls destructor and then release memory
    delete pc;
  
    // Calls the destructor for object pd[0]
    // and then release memory
    // and it does same for pd[1]
    delete [] pd;
  
    // No delete : Explicit call to Destructor.
    pe->~Complex();
  
    return 0;
}

Producción: 
 

Constructor : (4.2, 5.3)
Constructor : (0, 0)
Constructor : (0, 0)
Constructor : (2.6, 3.9)
|4.2 +j5.3 | = 6.7624
|0 +j0 | = 0
|0 +j0 | = 0
|2.6 +j3.9 | = 4.68722
Destructor : (4.2, 5.3)
Destructor : (0, 0)
Destructor : (0, 0)
Destructor : (2.6, 3.9)

Explicación: aquí se llama explícitamente al destructor porque aquí no se puede empaquetar dentro del operador de eliminación porque la eliminación necesitará liberar la memoria que no tiene aquí y no puede ser implícita ya que es un proceso dinámico que queremos administrar usted mismo. 
 

¿Cuándo la colocación del nuevo operador mostrará un error de segmentación?

La colocación del nuevo operador debe usarse con cuidado. La dirección que se pasa puede ser una referencia o un puntero que apunte a una ubicación de memoria válida. Puede mostrar un error cuando la dirección pasada es: 
 

  • Un puntero como puntero NULL.
  • Un puntero que no apunta a ninguna ubicación.
  • No puede ser un puntero vacío a menos que apunte a alguna ubicación.

CPP

// C++ program to illustrate segmentation fault
// while using placement new operator
#include<iostream>
using namespace std;
  
int main()
{
    // Fine
    int i = 10;
    int *ipt = &i ;
    int *i1 = new(ipt) int(9) ;
  
    // Incorrect as ip may not
    // be a valid address
    int *ip;
    int *i2 = new(ip) int(4) ;
  
    // Fine
    void *vd = &i;
    int *i3 = new(vd) int(34) ;
  
    // Incorrect as x is not an address
    int x;
    int *i5 = new(x) int(3) ;
  
    return 0;
}
Segmentation fault

Ventajas de colocar un nuevo operador sobre un nuevo operador

  • La dirección de asignación de memoria se conoce de antemano.
  • Útil cuando se crea un grupo de memoria, un recolector de basura o simplemente cuando el rendimiento y la seguridad de excepción son primordiales.
  • No hay peligro de falla en la asignación ya que la memoria ya se ha asignado, y la construcción de un objeto en un búfer preasignado lleva menos tiempo.
  • Esta función se vuelve útil cuando se trabaja en un entorno con recursos limitados.

Este artículo es una contribución de MAZHAR IMAM KHAN. Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *