¿Es seguro reasignar la memoria asignada con nuevo?


De lo que está escrito aquí, new asigna en free store mientras que mallocusa heap y los dos términos a menudo significan lo mismo.

De lo que está escrito aquí, realloc puede mover el bloque de memoria a una nueva ubicación. Si free store y heap son dos espacios de memoria diferentes, ¿significa entonces algún problema?

Específicamente me gustaría saber si es seguro de usar

int* data = new int[3];
// ...
int* mydata = (int*)realloc(data,6*sizeof(int));

Si no, hay alguna otra manera de realloc memoria asignada con new con seguridad? Podría asignar nueva área y memcpy el contenido, pero por lo que entiendo realloc puede usar la misma área si es posible.

Author: Community, 2015-11-14

9 answers

Solo se puede realloc lo que se ha asignado a través de malloc (o familia, como calloc).

Esto se debe a que las estructuras de datos subyacentes que hacen un seguimiento de las áreas libres y usadas de la memoria, pueden ser bastante diferentes.

Es probablemente pero de ninguna manera se garantiza que C++ new y C malloc usen el mismo asignador subyacente, en cuyo caso realloc podría funcionar para ambos. Pero formalmente eso es en UB-land. Y en la práctica es innecesariamente arriesgado.


C++ hace no ofrece la funcionalidad correspondiente a realloc.

Lo más cercano es la reasignación automática de (los búferes internos de) contenedores como std::vector.

Los contenedores de C++ sufren por estar diseñados de una manera que excluye el uso de realloc.


En lugar del código presentado

int* data = new int[3];
//...
int* mydata = (int*)realloc(data,6*sizeof(int));

Do haz esto:

vector<int> data( 3 );
//...
data.resize( 6 );

Sin embargo, si necesita absolutamente la eficiencia general de realloc, y si tiene que aceptar new para la asignación original, entonces su único el recurso para la eficiencia es usar medios específicos del compilador, conocimiento que realloc es seguro con este compilador.

De lo contrario, si necesita absolutamente la eficiencia general de realloc pero no está obligado a aceptar new, entonces puede usar malloc y realloc. El uso de punteros inteligentes le permite obtener gran parte de la misma seguridad que con los contenedores C++.

 44
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-17 12:54:25

La única restricción posiblemente relevante que C++ agrega a realloc es que malloc/calloc/realloc no debe implementarse en términos de ::operator new, y su free no debe implementarse en términos de ::operator delete (según C++14 [c. malloc] p3-4).

Esto significa que la garantía que está buscando no existe en C++. También significa, sin embargo, que puede implementar ::operator new en términos de malloc. Y si haces eso, entonces en teoría, el resultado de ::operator new se puede pasar a realloc.

En la práctica, usted debe ser preocupado por la posibilidad de que el resultado de new no coincida con el resultado de ::operator new. Los compiladores de C++ pueden, por ejemplo, combinar múltiples expresiones new para usar una sola llamada ::operator new. Esto es algo que los compiladores ya hicieron cuando el estándar no lo permitió, IIRC, y el estándar ahora lo permite (por C++14 [expr.nuevo]p10). Eso significa que incluso si vas por esta ruta, todavía no tienes una garantía de que pasar tus punteros new a realloc haga algo significativo, incluso si ya no está indefinido comportamiento.

 14
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 08:59:05

En general, no hagas eso. Si está utilizando tipos definidos por el usuario con inicialización no trivial, en caso de reallocation-copy-freeing, el destructor de sus objetos no será llamado por realloc. El constructor copy no será llamado también, al copiar. Esto puede llevar a un comportamiento indefinido debido a un uso incorrecto de duración del objeto (ver Estándar de C++ §3.8 Duración del objeto, [básico.vida]).

1 La vida de un objeto es un propiedad runtime del objeto. Se dice que un objeto tiene inicialización no trivial si es de tipo class o aggregate y él o uno de sus miembros es inicializado por un constructor que no sea un constructor por defecto trivial. [Nota: la inicialización por un constructor de copia/movimiento trivial es una inicialización no trivial. -nota final ]

La vida útil de un objeto de tipo T comienza cuando:

- se obtiene el almacenamiento con la alineación y el tamaño adecuados para el tipo T, y

- si el objeto tiene inicialización no trivial, su inicialización es completa.

La vida útil de un objeto de tipo T termina cuando:

- si T es un tipo de clase con un destructor no trivial (12.4), se inicia la llamada a destructor, o

- el almacenamiento que ocupa el objeto se reutiliza o libera.

Y más tarde (énfasis mío):

3 Las propiedades atribuidas a los objetos a lo largo de esta Norma Internacional se aplican a un determinado objeto solo durante su vida.

Por lo tanto, realmente no desea utilizar un objeto fuera de su vida.

 7
Author: Paolo M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 08:52:59

No es seguro, y no es elegante.

Podría ser posible anular new/delete para soportar la reasignación, pero entonces también puede considerar usar los contenedores.

 5
Author: Non-maskable Interrupt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 08:31:36

Sí-si new realmente llamó malloc en primer lugar (por ejemplo, así es como funciona VC++ new).

No de otra manera. tenga en cuenta que una vez que decida reasignar la memoria (porque new se llama malloc), su código es específico del compilador y ya no es portable entre compiladores.

(Sé que esta respuesta puede molestar a muchos desarrolladores, pero yo respondo depende de hechos reales, no solo idiomática).

 4
Author: David Haim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 08:39:42

Eso no es seguro. En primer lugar, el puntero que pasa a realloc debe haber sido obtenido de malloc o realloc: http://en.cppreference.com/w/cpp/memory/c/realloc .

En segundo lugar, el resultado de new int [3] no necesita ser el mismo que el resultado de la función de asignación: se puede asignar espacio adicional para almacenar el recuento de elementos.

(Y para tipos más complejos que int, realloc no sería seguro ya que no llama a copiar o mover constructores.)

 4
Author: Alan Stokes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 08:39:46

Puede (no en todos los casos), pero no debería. Si necesita cambiar el tamaño de su tabla de datos, debe usar std::vector en su lugar.

Los detalles sobre cómo usarlo se enumeran en otra pregunta SO.

 3
Author: nikaltipar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:10

En general, no.

Hay un montón de cosas que deben sostenerse para hacerlo seguro:

  1. Copiar el tipo a bit y abandonar la fuente debe ser seguro.
  2. El destructor debe ser trivial, o debe destruir en su lugar los elementos que desea desasignar.
  3. O bien el constructor es trivial, o debe construir in-place los nuevos elementos.

Los tipos triviales satisfacen los requisitos anteriores.

Además:

  1. El new[]-la función debe pasar la solicitud a malloc sin ningún cambio, ni hacer ninguna contabilidad en el lado. Puede forzar esto reemplazando global new[] y delete[], o los de las clases respectivas.
  2. El compilador no debe pedir más memoria para guardar el número de elementos asignados, o cualquier otra cosa.
    No hay manera de forzar eso, aunque un compilador no debería guardar dicha información si el tipo tiene un destructor trivial como una cuestión de Calidad de Aplicación .
 3
Author: Deduplicator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-15 10:42:55

Estas funciones se utilizan principalmente en C.

Memset establece los bytes en un bloque de memoria a un valor específico.

Malloc asigna un bloque de memoria.

Calloc, igual que malloc. La única diferencia es que inicializa los bytes a cero.

En C++ el método preferido para asignar memoria es usar new.

C: int IntArray = (int*) malloc (10 * sizeof (int)); C++: int IntArray = new int[10];

C: int IntArray = (int*) calloc (10 *sizeof(int)); C++: int IntArray = new int10;

 -1
Author: theDarkKnight,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 11:14:37