que - memoria dinamica en c++
¿Es seguro reasignar la memoria realloc con new? (9)
En general, no hagas eso. Si utiliza tipos definidos por el usuario con una inicialización no trivial , en el caso de reasignación-copia-liberación, el destructor de sus objetos no será llamado por realloc
. Tampoco se llamará al constructor de copia al copiar. Esto puede conducir a un comportamiento indefinido debido a un uso incorrecto de la duración del objeto (consulte el estándar C ++ §3.8 Vida útil del objeto, [basic.life] ).
1 La duración de un objeto es una propiedad de tiempo de ejecución del objeto. Se dice que un objeto tiene una inicialización no trivial si es de una clase o un tipo agregado y uno de sus miembros es inicializado por un constructor que no sea un constructor trivial predeterminado. [Nota: la inicialización por un constructor de copia / movimiento trivial es una inicialización no trivial. -Finalizar nota]
La vida útil de un objeto de tipo T comienza cuando:
- se obtiene un almacenamiento con la alineación y el tamaño adecuados para el tipo T, y
- si el objeto tiene una inicialización no trivial, su inicialización está completa.
La vida útil de un objeto de tipo T finaliza cuando:
- si T es un tipo de clase con un destructor no trivial (12.4), se inicia la llamada al destructor, o
- el almacenamiento que ocupa el objeto se reutiliza o libera.
Y luego (énfasis mío):
3 Las propiedades atribuidas a los objetos a lo largo de esta Norma Internacional se aplican a un objeto determinado solo durante su vigencia .
Entonces, realmente no quieres usar un objeto fuera de su tiempo de vida .
De lo que está escrito here , los new
asignan en la tienda gratuita mientras que malloc
usa montón y los dos términos a menudo significan lo mismo.
De lo que está escrito here , realloc
puede mover el bloque de memoria a una nueva ubicación. Si free store y heap son dos espacios de memoria diferentes, ¿significa algún problema entonces?
Específicamente, me gustaría saber si es seguro usar
int* data = new int[3];
// ...
int* mydata = (int*)realloc(data,6*sizeof(int));
Si no, ¿hay alguna otra manera de realloc
memoria realloc
con new
seguridad? Podría asignar nueva área y memcpy
los contenidos, pero por lo que entiendo, realloc
puede usar la misma área si es posible.
En general, no.
Hay una gran cantidad de cosas que deben mantenerse para que sea seguro:
- La copia a bitwise del tipo y el abandono de la fuente debe ser segura.
- El destructor debe ser trivial, o debe destruir en el lugar los elementos que desea desasignar.
- O el constructor es trivial, o debe construir en el lugar los nuevos elementos.
Los tipos triviales satisfacen los requisitos anteriores.
En adición:
- La
new[]
debe pasar la solicitud amalloc
sin ningún cambio, ni ninguna contabilidad en el lateral. Puede forzar esto al reemplazar global new [] y delete [], o los que están en las clases respectivas. - El compilador no debe pedir más memoria para guardar la cantidad de elementos asignados, o cualquier otra cosa.
No hay forma de forzar eso, aunque un compilador no debe guardar tal información si el tipo tiene un destructor trivial como una cuestión de Calidad de Implementación .
Es posible que puedas (no en todos los casos), pero no deberías. Si necesita cambiar el tamaño de su tabla de datos, debería usar std::vector
lugar.
Los detalles sobre cómo usarlo se enumeran en otra pregunta de SO .
Eso no es seguro. En primer lugar, el puntero que pasa a realloc
debe haberse obtenido de malloc
o realloc
: http://en.cppreference.com/w/cpp/memory/c/realloc .
En segundo lugar, el resultado de la new int [3]
no tiene que ser el mismo que el resultado de la función de asignación; se puede asignar espacio extra 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).
Esta función se usa principalmente en C.
memset establece los bytes en un bloque de memoria a un valor específico.
malloc asigna un bloque de memoria.
calloc, lo mismo que malloc. La única diferencia es que inicializa los bytes a cero.
En C ++, el método preferido para asignar memoria es usar nuevo.
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;
La única restricción posiblemente relevante que C ++ agrega a realloc
es que el malloc
/ calloc
/ realloc
C ++ no debe implementarse en términos de ::operator new
, y su free
no debe implementarse en términos de ::operator delete
(por 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, debería preocuparse por la posibilidad de que el resultado new
no coincida con el resultado ::operator new
. Los compiladores C ++ pueden, por ejemplo, combinar múltiples expresiones new
para usar una única llamada ::operator new
. Esto es algo que los compiladores ya hacían cuando el estándar no lo permitía, IIRC, y el estándar ahora lo permite (por C ++ 14 [expr.new] p10). Eso significa que incluso si sigue esta ruta, aún no tiene una garantía de que pasar los new
punteros a realloc
sea significativo, incluso si ya no es un comportamiento indefinido.
No es seguro, y no es elegante.
Es posible anular el nuevo / eliminar para respaldar la reasignación, pero también puede considerar usar los contenedores.
Sí, si en realidad se llama malloc
en primer lugar (por ejemplo, así es como funciona VC ++).
No de otra manera tenga en cuenta que una vez que decide reasignar la memoria (porque new
llamada malloc
), su código es específico del compilador y ya no es portátil entre los compiladores.
(Sé que esta respuesta puede molestar a muchos desarrolladores, pero la respuesta depende de hechos reales, no solo de idiomática).
Solo puedes realloc
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 de memoria libres y usadas, pueden ser bastante diferentes.
Es probable, 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 está en UB-land. Y en la práctica es innecesariamente arriesgado.
C ++ 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 C ++ sufren de 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));
… hacer esto:
vector<int> data( 3 );
//...
data.resize( 6 );
Sin embargo, si necesita absolutamente la eficiencia general de realloc
, y si tiene que aceptar algo new
para la asignación original, entonces su único recurso para la eficiencia es usar medios específicos del compilador, saber 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 la misma seguridad que con los contenedores de C ++.