Espacios de nombres
Variantes
Acciones

Expresión new

De cppreference.com
< cpp‎ | language
 
 
 
 

Crea e inicializa objetos duración de almacenamiento dinámica. Es decir, objetos cuya duración no se limita al ámbito en el que se crearon.

Contenido

[editar]Sintaxis

::(opcional)new(params_de_ubicación)(opcional)(tipo)inicializador(opcional) (1)
::(opcional)new(params_de_ubicación)(opcional)tipoinicializador(opcional) (2)
1) Intenta crear un objeto de tipo, denotado por el id de tipotipo, que puede ser un tipo de array, y puede incluir un especificador de tipo marcador de posición(desde C++11), o incluir una plantilla de clase cuyo argumento se deducirá mediante la deducción de argumentos de plantillas de clase(desde C++17).
2) Lo mismo, pero tipo no puede incluir paréntesis:
new int(*[10])();// ERROR: analizado como (new int) (*[10]) () new (int(*[10])());// de acuerdo: asigna un array de 10 punteros a funciones

Además, el tipo sin paréntesis es voraz: incluirá todos los símbolos que puedan ser parte de un declarador:

new int+1;// de acuerdo: analizado como (new int) + 1,// incrementa un puntero devuelto por new int new int*1;// ERROR: analizado como (new int*) (1)

El inicializador no es opcional si:

auto p = new auto('c');// crea un solo objeto de tipo. p es un char*double* p = new double[]{1,2,3};// crea un array de tipo double[3]

[editar]Explicación

La expresión new intenta asignar almacenamiento y luego intenta construir e inicializar un solo objeto sin nombre o un array de objetos sin nombre en el almacenamiento asignado. La expresión new devuelve un puntero prvalue al objeto construido o, si se construyó un array de objetos, un puntero al elemento inicial del array.

Si tipo es un tipo de array, todas las dimensiones excepto la primera deben de especificarse como una expresión constante entera(hasta C++14)expresión constante convertida de tipo std::size_t(desde C++14) positiva, pero (solamente cuando se usa la sintaxis sin paréntesis (2)) la primera dimensión puede ser cualquier expresión convertible a std::size_t. Esta es la única manera de crear directamente un array con un tamaño definido en tiempo de ejecución. Tales arrays son referidos frecuentemente como arrays dinámicos:

int n =42;double a[n][5];// ERRORauto p1 = new double[n][5];// de acuerdoauto p2 = new double[5][n];// ERROR, solamente la primera dimensión puede ser variableauto p3 = new (double[n][5]);// ERROR, sintaxis (1) no puede usarse para arrays dinámicos

En los casos siguientes la expresión que especifica la primera dimensión es errónea:

  • la expresión es de un tipo de no-clase y su valor antes de la conversión a std::size_t es negativo;
  • la expresión es de un tipo de clase y su valor después de la función de conversión definida por el usuario y antes de la segunda conversión estándar es negativo;
  • el valor de la expresión es más grande que algún límite definido por la implementación;
  • el valor es más pequeño que el número de elementos del array proporcionados en el inicializador entre llaves (incluyendo el terminador '\0' en un literal de cadena).

Si el valor en la primera dimensión es erróneo por cualquiera de estas razones:

  • De otra forma, si la función de asignación que se hubiera llamado no lanza, la expresión new devuelve el puntero nulo del tipo de resultado requerido.
(desde C++14)
  • De otra forma, la expresión new no llama a la función de asignación, y en su lugar lanza una excepción de tipo std::bad_array_new_length o una excepción derivada de ella.
(desde C++11)

La primera dimensión de cero es aceptable, y se llama a la función de asignación.

Nota: std::vector ofrece una funcionalidad similar para arrays dinámicos unidimensionales.

[editar]Asignación

La expresión new asigna almacenamiento llamando a la función de asignación apropriada. Si tipo es un tipo que no es array, el nombre de la función es operator new. Si tipo es un tipo de array, el nombre de la función es operator new[].

Como se describe en la función de asignación, el programa de C++ puede proporcionar reemplazos globales y específicos de clase para estas funciones. Si la expresión new comienza con el operador opcional ::, como en ::new T o ::new T [n] , los reemplazos específicos de la clase serán ignorados (la función es buscada en el ámbito global). De lo contrario, si T es un tipo de clase, la búsqueda comienza en el ámbito de clase de T.

Al llamar a la función de asignación, la expresión new pasa el número de bytes solicitados como primer argumento, de tipo std::size_t, que es exactamente sizeof(T) para una T que no es un array.

La asignación de un array puede suplementar un valor adicional no especificado, que puede variar de una llamada a new a la siguiente. El puntero devuelto por la expresión new será compensado con ese valor adicional del puntero devuelto por la función de asignación. Muchas implementaciones usan ese valor adicional del array para almacenar el número de objetos en el array, que se utiliza por la expresión delete [] para llamar al número correcto de destructores. Además, si la expresión new se usa para asignar un array de char, unsignedchar, o std::byte, puede solicitar memoria adicional de la función de asignación si es necesario para garantizar la alineación correcta de los objetos de todos los tipos que no sean mayores que el tamaño del array solicitado, si luego se coloca uno de tales objetos en el array asignado.

Se permite que las expresiones new elidan o combinen asignaciones hechas mediante funciones de asignación. En el caso de elisión, el almacenamiento puede proporcionarse por el compilador sin hacer la llamada a la función de asignación (esto también permite optimizar expresiones new no usadas). En el caso de combinación, la asignación hecha por una expresión new E1 puede extenderse para proporcionar almacenamiento adicional para otra expresión new E2 si todo lo siguiente es verdadero:

1) La duración del objeto asignado por E1 contiene estrictamente la duración del objeto asignado por E2.
2) E1 y E2 invocarían la misma función de asignación global reemplazable.
3) Para una función de asignación que lanza, las excepciones en E1 y E2 serían primero atrapadas en el mismo controlador.

Observa que esta optimización solamente se permite cuando se usan las expresiones new, no cuando se usa cualquier otro método para llamar a una función de asignación reemplazable: delete[] new int[10]; puede optimizarse, pero operator delete(operator new(10)); no.

(desde C++14)

Durante una evaluación de una expresión constante, una llamada a una función de asignación siempre se omite. Solamente las expresiones new que de otra manera resultarían en una llamada a una función de asignación global reemplazable pueden evaluarse en expresiones constantes.

(desde C++20)
[editar]New de ubicación

Si se proporcionan params_de_ubicación se pasan a la función de asignación como argumentos adicionales. Tales funciones de asdignación se conocen como "new de ubicación", debido a la función de asignación estándar void*operator new(std::size_t, void*), que simplemente devuelve su segundo argumento sin cambiarlo. Esto se utiliza para construir objetos en almacenamiento asignado:

char* ptr = new char[sizeof(T)];// asignar memoria T* tptr = new(ptr) T;// construir en almacenamiento asignado ("ubicar") tptr->~T();// destruir delete[] ptr;// desasignar memoria

Nota: esta funcionalidad se encapsula por las funciones miembro de las clases Allocator.

Cuando se asigna un objeto cuyo requerimiento de alineación excede __STDCPP_DEFAULT_NEW_ALIGNMENT__ o un array de tales objetos, la expresión new pasa el requerimiento de alineación (envuelto en std::align_val_t) como el segundo argumento para la función de asignación (para las formas de ubicación, los params_de_ubicación aparecen después de la alineación, como el tercero, cuarto, etc., argumentos). Si la resolución de sobrecarga falla (que sucede cuando se define una función de asignación específica de una clase con una signatura diferente, ya que oculta las globales), la resolución de sobrecarga se intenta por segunda vez, sin la alineación en la lista de argumentos. Esto permite que las funciones de asignación específicas de una clase que no están conscientes de la alineación tengan precedencia sobre las funciones de asignación globales conscientes de la alineación.

(desde C++17)
new T;// llama al operador new(sizeof(T))// (C++17) o al operador new(sizeof(T), std::align_val_t(alignof(T)))) new T[5];// llama al operador new[](sizeof(T)*5 + overhead)// (C++17) o al operador new(sizeof(T)*5+overhead, std::align_val_t(alignof(T)))) new(2,f) T;// llama al operador new(sizeof(T), 2, f)// (C++17) o al operador new(sizeof(T), std::align_val_t(alignof(T)), 2, f)

Si la función de asignación devuelve un puntero nulo, lo cual es posible si se seleccionó la sobrecarga que no lanza, p. ej., con new(std::nothrow) T;, entonces la expresión new regresa inmediatamente, no intenta inicializar un objeto o llamar a una función de desasignación. Si la función de asignación de ubicación estándar devuelve un puntero nulo, que es posible si el usuario pasa un puntero nulo como argumento, el comportamiento es indefinido.(desde C++17)

[editar]Construcción

El objeto creado por una expresión new se inicializa de acuerdo a las siguientes reglas:

  • Para un tipo que no es array, el objeto individual se construye en el área de memoria adquirida.
  • Si inicializador es una lista de argumentos entre llaves, el objeto es inicializado mediante la inicialización de lista.
(desde C++11)
  • Si tipo es un tipo de array, se inicializa un array de objetos.
(desde C++11)
(desde C++20)

Si la inicialización termina lanzando una excepción (por ejemplo, del constructor), si expresión new asignó algún almacenamiento, llama a la función de desasignación apropiada: operator delete cuando tipo no es de tipo array, operator delete[] cuando tipo es un tipo de array. La función de desasignación se busca en el ámbito global si la expresión new utiliza la sintaxis ::new, de lo contrario, se busca en el ámbito de T, si T es un tipo de clase. Si la función de asignación fallida era la habitual (sin colocación), la búsqueda de la función de desasignación sigue las reglas descritas en la expresión delete. Para new de ubicación fallida, todos los tipos de parámetros, excepto el primero, de la función de desasignación coincidente deben ser idénticos a los parámetros de new de ubicación. La llamada a la función de desasignación se convierte en el valor obtenido anteriormente de la función de asignación pasada como primer argumento, la alineación pasada como el argumento de alineación opcional(desde C++17), y params_de_ubicación , si hay alguno, pasados como argumentos de ubicación adicionales. Si no se encuentra ninguna función de desasignación, la memoria no se desasigna.

[editar]Fugas de memoria

Los objetos creados por las expresiones new (objetos con duración de almacenamiento dinámica) persisten hasta que el puntero devuelto por la expresión new se usa en una expresión delete coincidente. Si el valor original del puntero se pierde, el objeto se vuelve inalcanzable y no puede desasignarse: ocurre una fuga de memoria.

Esto puede suceder si se asigna al puntero:

int* p = new int(7);// int asignado dinámicamente con el valor 7 p = nullptr;// fuga de memoria

o si el puntero sale de ámbito:

void f(){int* p = new int(7);}// fuga de memoria

o debido a una excepción

void f(){int* p = new int(7); g();// puede lanzar delete p;// de acuerdo si no hay excepción}// fuga de memoria si g() lanza

Para simplificar la administración de objetos asignados dinámicamente, el resultado de una expresión new frecuentemente se almacena en un puntero inteligente: std::auto_ptr(hasta C++17)std::unique_ptr, o std::shared_ptr(desde C++11). Estos punteros garantizan que la expresión delete se ejecuta en las situaciones mostradas anteriormente.

[editar]Palabras clave

new


[editar]Informes de defectos

Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.

ID Aplicado a Comportamiento según lo publicado Comportamiento correcto
CWG 1992 C++14 new (std::nothrow) int[N] podía lanzar bad_array_new_length. Se cambió para que devolviera un puntero nulo.
P1009R2 C++11 El límite del array no se puede deducir en una expresión new. Se permite la deducción.

[editar]Véase también

close