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.
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.
¿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